blob: 27e02efb065b3dd35bb9473ddfe29027600562cb [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 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"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000045#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000047#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000048#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000049#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000050#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000051#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000053#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000056#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000058#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000059#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000060#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062namespace v8 {
63namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65
ager@chromium.org3e875802009-06-29 08:26:34 +000066#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
69// Cast the given object to a value of the specified type and store
70// it in a variable with the given name. If the object is not of the
71// expected type call IllegalOperation and return.
72#define CONVERT_CHECKED(Type, name, obj) \
73 RUNTIME_ASSERT(obj->Is##Type()); \
74 Type* name = Type::cast(obj);
75
76#define CONVERT_ARG_CHECKED(Type, name, index) \
77 RUNTIME_ASSERT(args[index]->Is##Type()); \
78 Handle<Type> name = args.at<Type>(index);
79
kasper.lundbd3ec4e2008-07-09 11:06:54 +000080// Cast the given object to a boolean and store it in a variable with
81// the given name. If the object is not a boolean call IllegalOperation
82// and return.
83#define CONVERT_BOOLEAN_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsBoolean()); \
85 bool name = (obj)->IsTrue();
86
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000087// Cast the given argument to a Smi and store its value in an int variable
88// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000089// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000090#define CONVERT_SMI_ARG_CHECKED(name, index) \
91 RUNTIME_ASSERT(args[index]->IsSmi()); \
92 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000093
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000094// Cast the given argument to a double and store it in a variable with
95// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000097#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
98 RUNTIME_ASSERT(args[index]->IsNumber()); \
99 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101// Call the specified converter on the object *comand store the result in
102// a variable of the specified type with the given name. If the
103// object is not a Number call IllegalOperation and return.
104#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
105 RUNTIME_ASSERT(obj->IsNumber()); \
106 type name = NumberTo##Type(obj);
107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000109// Assert that the given argument has a valid value for a StrictModeFlag
110// and store it in a StrictModeFlag variable with the given name.
111#define CONVERT_STRICT_MODE_ARG(name, index) \
112 ASSERT(args[index]->IsSmi()); \
113 ASSERT(args.smi_at(index) == kStrictMode || \
114 args.smi_at(index) == kNonStrictMode); \
115 StrictModeFlag name = \
116 static_cast<StrictModeFlag>(args.smi_at(index));
117
118
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000119MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
120 JSObject* boilerplate) {
121 StackLimitCheck check(isolate);
122 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000123
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000124 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000125 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000126 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000127 if (!maybe_result->ToObject(&result)) return maybe_result;
128 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000129 JSObject* copy = JSObject::cast(result);
130
131 // Deep copy local properties.
132 if (copy->HasFastProperties()) {
133 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000134 for (int i = 0; i < properties->length(); i++) {
135 Object* value = properties->get(i);
136 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000137 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000138 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000139 if (!maybe_result->ToObject(&result)) return maybe_result;
140 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000141 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000142 }
143 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000144 int nof = copy->map()->inobject_properties();
145 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000146 Object* value = copy->InObjectPropertyAt(i);
147 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000148 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000149 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000150 if (!maybe_result->ToObject(&result)) return maybe_result;
151 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 }
154 }
155 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000156 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000157 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000158 if (!maybe_result->ToObject(&result)) return maybe_result;
159 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000160 FixedArray* names = FixedArray::cast(result);
161 copy->GetLocalPropertyNames(names, 0);
162 for (int i = 0; i < names->length(); i++) {
163 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000164 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000165 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000166 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000167 // Only deep copy fields from the object literal expression.
168 // In particular, don't try to copy the length attribute of
169 // an array.
170 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000171 Object* value =
172 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000173 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000174 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000175 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000176 if (!maybe_result->ToObject(&result)) return maybe_result;
177 }
178 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000179 // Creating object copy for literals. No strict mode needed.
180 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000181 if (!maybe_result->ToObject(&result)) return maybe_result;
182 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000183 }
184 }
185 }
186
187 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000188 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000189 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000190 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000191 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000192 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000193 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000194 if (elements->map() == heap->fixed_cow_array_map()) {
195 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000196#ifdef DEBUG
197 for (int i = 0; i < elements->length(); i++) {
198 ASSERT(!elements->get(i)->IsJSObject());
199 }
200#endif
201 } else {
202 for (int i = 0; i < elements->length(); i++) {
203 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000204 ASSERT(value->IsSmi() ||
205 value->IsTheHole() ||
206 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000207 if (value->IsJSObject()) {
208 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000209 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
210 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000211 if (!maybe_result->ToObject(&result)) return maybe_result;
212 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000213 elements->set(i, result);
214 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000215 }
216 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000217 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000218 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000219 case DICTIONARY_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000220 NumberDictionary* element_dictionary = copy->element_dictionary();
221 int capacity = element_dictionary->Capacity();
222 for (int i = 0; i < capacity; i++) {
223 Object* k = element_dictionary->KeyAt(i);
224 if (element_dictionary->IsKey(k)) {
225 Object* value = element_dictionary->ValueAt(i);
226 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000227 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000228 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
229 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000230 if (!maybe_result->ToObject(&result)) return maybe_result;
231 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000232 element_dictionary->ValueAtPut(i, result);
233 }
234 }
235 }
236 break;
237 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000238 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000239 UNIMPLEMENTED();
240 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000241 case EXTERNAL_PIXEL_ELEMENTS:
242 case EXTERNAL_BYTE_ELEMENTS:
243 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
244 case EXTERNAL_SHORT_ELEMENTS:
245 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
246 case EXTERNAL_INT_ELEMENTS:
247 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
248 case EXTERNAL_FLOAT_ELEMENTS:
249 case EXTERNAL_DOUBLE_ELEMENTS:
250 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000251 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000252 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000253 }
254 return copy;
255}
256
257
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000258RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000259 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000260 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000261}
262
263
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000264RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000265 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000266 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000267}
268
269
ager@chromium.org236ad962008-09-25 09:45:57 +0000270static Handle<Map> ComputeObjectLiteralMap(
271 Handle<Context> context,
272 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000273 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000274 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000275 int properties_length = constant_properties->length();
276 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000277 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000278 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000279 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000280 for (int p = 0; p != properties_length; p += 2) {
281 Object* key = constant_properties->get(p);
282 uint32_t element_index = 0;
283 if (key->IsSymbol()) {
284 number_of_symbol_keys++;
285 } else if (key->ToArrayIndex(&element_index)) {
286 // An index key does not require space in the property backing store.
287 number_of_properties--;
288 } else {
289 // Bail out as a non-symbol non-index key makes caching impossible.
290 // ASSERT to make sure that the if condition after the loop is false.
291 ASSERT(number_of_symbol_keys != number_of_properties);
292 break;
293 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000294 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000295 // If we only have symbols and array indices among keys then we can
296 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000297 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000298 if ((number_of_symbol_keys == number_of_properties) &&
299 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000300 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000301 Handle<FixedArray> keys =
302 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000303 if (number_of_symbol_keys > 0) {
304 int index = 0;
305 for (int p = 0; p < properties_length; p += 2) {
306 Object* key = constant_properties->get(p);
307 if (key->IsSymbol()) {
308 keys->set(index++, key);
309 }
310 }
311 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000312 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000313 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000314 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000315 }
316 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000317 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000318 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000319 Handle<Map>(context->object_function()->initial_map()),
320 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000321}
322
323
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000324static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000325 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000326 Handle<FixedArray> literals,
327 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000328
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000329
330static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000331 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000332 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000333 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000334 bool should_have_fast_elements,
335 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000336 // Get the global context from the literals array. This is the
337 // context in which the function was created and we use the object
338 // function from this context to create the object literal. We do
339 // not use the object function from the current global context
340 // because this might be the object function from another context
341 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000342 Handle<Context> context =
343 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
344
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000345 // In case we have function literals, we want the object to be in
346 // slow properties mode for now. We don't go in the map cache because
347 // maps with constant functions can't be shared if the functions are
348 // not the same (which is the common case).
349 bool is_result_from_cache = false;
350 Handle<Map> map = has_function_literal
351 ? Handle<Map>(context->object_function()->initial_map())
352 : ComputeObjectLiteralMap(context,
353 constant_properties,
354 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000356 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000357
358 // Normalize the elements of the boilerplate to save space if needed.
359 if (!should_have_fast_elements) NormalizeElements(boilerplate);
360
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000361 // Add the constant properties to the boilerplate.
362 int length = constant_properties->length();
363 bool should_transform =
364 !is_result_from_cache && boilerplate->HasFastProperties();
365 if (should_transform || has_function_literal) {
366 // Normalize the properties of object to avoid n^2 behavior
367 // when extending the object multiple properties. Indicate the number of
368 // properties to be added.
369 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
370 }
371
372 for (int index = 0; index < length; index +=2) {
373 Handle<Object> key(constant_properties->get(index+0), isolate);
374 Handle<Object> value(constant_properties->get(index+1), isolate);
375 if (value->IsFixedArray()) {
376 // The value contains the constant_properties of a
377 // simple object or array literal.
378 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
379 value = CreateLiteralBoilerplate(isolate, literals, array);
380 if (value.is_null()) return value;
381 }
382 Handle<Object> result;
383 uint32_t element_index = 0;
384 if (key->IsSymbol()) {
385 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
386 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000387 result = SetOwnElement(boilerplate,
388 element_index,
389 value,
390 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000391 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000392 Handle<String> name(String::cast(*key));
393 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000394 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
395 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000396 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000397 } else if (key->ToArrayIndex(&element_index)) {
398 // Array index (uint32).
399 result = SetOwnElement(boilerplate,
400 element_index,
401 value,
402 kNonStrictMode);
403 } else {
404 // Non-uint32 number.
405 ASSERT(key->IsNumber());
406 double num = key->Number();
407 char arr[100];
408 Vector<char> buffer(arr, ARRAY_SIZE(arr));
409 const char* str = DoubleToCString(num, buffer);
410 Handle<String> name =
411 isolate->factory()->NewStringFromAscii(CStrVector(str));
412 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
413 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000415 // If setting the property on the boilerplate throws an
416 // exception, the exception is converted to an empty handle in
417 // the handle based operations. In that case, we need to
418 // convert back to an exception.
419 if (result.is_null()) return result;
420 }
421
422 // Transform to fast properties if necessary. For object literals with
423 // containing function literals we defer this operation until after all
424 // computed properties have been assigned so that we can generate
425 // constant function properties.
426 if (should_transform && !has_function_literal) {
427 TransformToFastProperties(boilerplate,
428 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000429 }
430
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000431 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000432}
433
434
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000435static const int kSmiOnlyLiteralMinimumLength = 1024;
436
437
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000438static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000439 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000440 Handle<FixedArray> literals,
441 Handle<FixedArray> elements) {
442 // Create the JSArray.
443 Handle<JSFunction> constructor(
444 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000445 Handle<JSArray> object =
446 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000447
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000448 ElementsKind constant_elements_kind =
449 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
450 Handle<FixedArrayBase> constant_elements_values(
451 FixedArrayBase::cast(elements->get(1)));
452
453 ASSERT(FLAG_smi_only_arrays || constant_elements_kind == FAST_ELEMENTS ||
454 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS);
455 bool allow_literal_kind_transition = FLAG_smi_only_arrays &&
456 constant_elements_kind > object->GetElementsKind();
457
458 if (!FLAG_smi_only_arrays &&
459 constant_elements_values->length() > kSmiOnlyLiteralMinimumLength &&
460 constant_elements_kind != object->GetElementsKind()) {
461 allow_literal_kind_transition = true;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000462 }
463
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000464 // If the ElementsKind of the constant values of the array literal are less
465 // specific than the ElementsKind of the boilerplate array object, change the
466 // boilerplate array object's map to reflect that kind.
467 if (allow_literal_kind_transition) {
468 Handle<Map> transitioned_array_map =
469 isolate->factory()->GetElementsTransitionMap(object,
470 constant_elements_kind);
471 object->set_map(*transitioned_array_map);
472 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000473
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000474 Handle<FixedArrayBase> copied_elements_values;
475 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
476 ASSERT(FLAG_smi_only_arrays);
477 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
478 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000479 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000480 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
481 constant_elements_kind == FAST_ELEMENTS);
482 const bool is_cow =
483 (constant_elements_values->map() ==
484 isolate->heap()->fixed_cow_array_map());
485 if (is_cow) {
486 copied_elements_values = constant_elements_values;
487#if DEBUG
488 Handle<FixedArray> fixed_array_values =
489 Handle<FixedArray>::cast(copied_elements_values);
490 for (int i = 0; i < fixed_array_values->length(); i++) {
491 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
492 }
493#endif
494 } else {
495 Handle<FixedArray> fixed_array_values =
496 Handle<FixedArray>::cast(constant_elements_values);
497 Handle<FixedArray> fixed_array_values_copy =
498 isolate->factory()->CopyFixedArray(fixed_array_values);
499 copied_elements_values = fixed_array_values_copy;
500 for (int i = 0; i < fixed_array_values->length(); i++) {
501 Object* current = fixed_array_values->get(i);
502 if (current->IsFixedArray()) {
503 // The value contains the constant_properties of a
504 // simple object or array literal.
505 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
506 Handle<Object> result =
507 CreateLiteralBoilerplate(isolate, literals, fa);
508 if (result.is_null()) return result;
509 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000510 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000511 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000512 }
513 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000514 object->set_elements(*copied_elements_values);
515 object->set_length(Smi::FromInt(copied_elements_values->length()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000516 return object;
517}
518
519
520static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000521 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000522 Handle<FixedArray> literals,
523 Handle<FixedArray> array) {
524 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000525 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000526 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000527 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 return CreateObjectLiteralBoilerplate(isolate,
529 literals,
530 elements,
531 true,
532 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000533 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000534 return CreateObjectLiteralBoilerplate(isolate,
535 literals,
536 elements,
537 false,
538 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000539 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000540 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000541 default:
542 UNREACHABLE();
543 return Handle<Object>::null();
544 }
545}
546
547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000548RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000549 // Takes a FixedArray of elements containing the literal elements of
550 // the array literal and produces JSArray with those elements.
551 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000552 // which contains the context from which to get the Array function
553 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000554 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000555 ASSERT(args.length() == 3);
556 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000557 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000558 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000559
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000560 Handle<Object> object =
561 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000562 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000563
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000564 // Update the functions literal and return the boilerplate.
565 literals->set(literals_index, *object);
566 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000567}
568
569
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000570RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000571 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000572 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000573 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000574 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000575 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000576 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
578 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000579
580 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000581 Handle<Object> boilerplate(literals->get(literals_index), isolate);
582 if (*boilerplate == isolate->heap()->undefined_value()) {
583 boilerplate = CreateObjectLiteralBoilerplate(isolate,
584 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000585 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000586 should_have_fast_elements,
587 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000588 if (boilerplate.is_null()) return Failure::Exception();
589 // Update the functions literal and return the boilerplate.
590 literals->set(literals_index, *boilerplate);
591 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000592 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000593}
594
595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000596RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000597 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000598 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000599 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000600 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000601 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000602 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000603 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
604 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000605
606 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000607 Handle<Object> boilerplate(literals->get(literals_index), isolate);
608 if (*boilerplate == isolate->heap()->undefined_value()) {
609 boilerplate = CreateObjectLiteralBoilerplate(isolate,
610 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000611 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000612 should_have_fast_elements,
613 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000614 if (boilerplate.is_null()) return Failure::Exception();
615 // Update the functions literal and return the boilerplate.
616 literals->set(literals_index, *boilerplate);
617 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000618 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000619}
620
621
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000622RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000623 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000624 ASSERT(args.length() == 3);
625 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000626 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000627 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
628
629 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000630 Handle<Object> boilerplate(literals->get(literals_index), isolate);
631 if (*boilerplate == isolate->heap()->undefined_value()) {
632 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000633 if (boilerplate.is_null()) return Failure::Exception();
634 // Update the functions literal and return the boilerplate.
635 literals->set(literals_index, *boilerplate);
636 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000637 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000638}
639
640
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000641RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000642 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000643 ASSERT(args.length() == 3);
644 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000645 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000646 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
647
648 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000649 Handle<Object> boilerplate(literals->get(literals_index), isolate);
650 if (*boilerplate == isolate->heap()->undefined_value()) {
651 boilerplate = 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);
703 CONVERT_CHECKED(JSProxy, proxy, args[0]);
704 return proxy->handler();
705}
706
707
lrn@chromium.org34e60782011-09-15 07:25:40 +0000708RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
709 ASSERT(args.length() == 1);
710 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
711 return proxy->call_trap();
712}
713
714
715RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
716 ASSERT(args.length() == 1);
717 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
718 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);
724 CONVERT_CHECKED(JSProxy, proxy, args[0]);
725 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);
733 CONVERT_ARG_CHECKED(JSSet, holder, 0);
734 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);
743 CONVERT_ARG_CHECKED(JSSet, holder, 0);
744 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);
755 CONVERT_ARG_CHECKED(JSSet, holder, 0);
756 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);
765 CONVERT_ARG_CHECKED(JSSet, holder, 0);
766 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);
777 CONVERT_ARG_CHECKED(JSMap, holder, 0);
778 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);
787 CONVERT_ARG_CHECKED(JSMap, holder, 0);
788 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);
796 CONVERT_ARG_CHECKED(JSMap, holder, 0);
797 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);
809 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
810 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);
821 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000822 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
823 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);
830 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000831 CONVERT_ARG_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);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000852 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
853 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
ager@chromium.org9085a012009-05-11 19:22:57 +0000886// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000887RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000888 NoHandleAllocation ha;
889 ASSERT(args.length() == 2);
890 CONVERT_CHECKED(JSObject, jsobject, args[0]);
891 CONVERT_CHECKED(JSObject, proto, args[1]);
892
893 // Sanity checks. The old prototype (that we are replacing) could
894 // theoretically be null, but if it is not null then check that we
895 // didn't already install a hidden prototype here.
896 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
897 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
898 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
899
900 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000901 Object* map_or_failure;
902 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
903 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
904 return maybe_map_or_failure;
905 }
906 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000907 Map* new_proto_map = Map::cast(map_or_failure);
908
lrn@chromium.org303ada72010-10-27 09:33:13 +0000909 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
910 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
911 return maybe_map_or_failure;
912 }
913 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000914 Map* new_map = Map::cast(map_or_failure);
915
916 // Set proto's prototype to be the old prototype of the object.
917 new_proto_map->set_prototype(jsobject->GetPrototype());
918 proto->set_map(new_proto_map);
919 new_proto_map->set_is_hidden_prototype();
920
921 // Set the object's prototype to proto.
922 new_map->set_prototype(proto);
923 jsobject->set_map(new_map);
924
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000925 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000926}
927
928
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000929RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000930 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000931 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000932 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000933 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000934}
935
936
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000937// Recursively traverses hidden prototypes if property is not found
938static void GetOwnPropertyImplementation(JSObject* obj,
939 String* name,
940 LookupResult* result) {
941 obj->LocalLookupRealNamedProperty(name, result);
942
943 if (!result->IsProperty()) {
944 Object* proto = obj->GetPrototype();
945 if (proto->IsJSObject() &&
946 JSObject::cast(proto)->map()->is_hidden_prototype())
947 GetOwnPropertyImplementation(JSObject::cast(proto),
948 name, result);
949 }
950}
951
952
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000953static bool CheckAccessException(LookupResult* result,
954 v8::AccessType access_type) {
955 if (result->type() == CALLBACKS) {
956 Object* callback = result->GetCallbackObject();
957 if (callback->IsAccessorInfo()) {
958 AccessorInfo* info = AccessorInfo::cast(callback);
959 bool can_access =
960 (access_type == v8::ACCESS_HAS &&
961 (info->all_can_read() || info->all_can_write())) ||
962 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
963 (access_type == v8::ACCESS_SET && info->all_can_write());
964 return can_access;
965 }
966 }
967
968 return false;
969}
970
971
972static bool CheckAccess(JSObject* obj,
973 String* name,
974 LookupResult* result,
975 v8::AccessType access_type) {
976 ASSERT(result->IsProperty());
977
978 JSObject* holder = result->holder();
979 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000980 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000981 while (true) {
982 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000983 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000984 // Access check callback denied the access, but some properties
985 // can have a special permissions which override callbacks descision
986 // (currently see v8::AccessControl).
987 break;
988 }
989
990 if (current == holder) {
991 return true;
992 }
993
994 current = JSObject::cast(current->GetPrototype());
995 }
996
997 // API callbacks can have per callback access exceptions.
998 switch (result->type()) {
999 case CALLBACKS: {
1000 if (CheckAccessException(result, access_type)) {
1001 return true;
1002 }
1003 break;
1004 }
1005 case INTERCEPTOR: {
1006 // If the object has an interceptor, try real named properties.
1007 // Overwrite the result to fetch the correct property later.
1008 holder->LookupRealNamedProperty(name, result);
1009 if (result->IsProperty()) {
1010 if (CheckAccessException(result, access_type)) {
1011 return true;
1012 }
1013 }
1014 break;
1015 }
1016 default:
1017 break;
1018 }
1019
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001020 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001021 return false;
1022}
1023
1024
1025// TODO(1095): we should traverse hidden prototype hierachy as well.
1026static bool CheckElementAccess(JSObject* obj,
1027 uint32_t index,
1028 v8::AccessType access_type) {
1029 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001030 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001031 return false;
1032 }
1033
1034 return true;
1035}
1036
1037
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001038// Enumerator used as indices into the array returned from GetOwnProperty
1039enum PropertyDescriptorIndices {
1040 IS_ACCESSOR_INDEX,
1041 VALUE_INDEX,
1042 GETTER_INDEX,
1043 SETTER_INDEX,
1044 WRITABLE_INDEX,
1045 ENUMERABLE_INDEX,
1046 CONFIGURABLE_INDEX,
1047 DESCRIPTOR_SIZE
1048};
1049
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001050// Returns an array with the property description:
1051// if args[1] is not a property on args[0]
1052// returns undefined
1053// if args[1] is a data property on args[0]
1054// [false, value, Writeable, Enumerable, Configurable]
1055// if args[1] is an accessor on args[0]
1056// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001057RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001058 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001059 Heap* heap = isolate->heap();
1060 HandleScope scope(isolate);
1061 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1062 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001063 LookupResult result(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001064 CONVERT_ARG_CHECKED(JSObject, obj, 0);
1065 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001066
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001067 // This could be an element.
1068 uint32_t index;
1069 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001070 switch (obj->HasLocalElement(index)) {
1071 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001072 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001073
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001074 case JSObject::STRING_CHARACTER_ELEMENT: {
1075 // Special handling of string objects according to ECMAScript 5
1076 // 15.5.5.2. Note that this might be a string object with elements
1077 // other than the actual string value. This is covered by the
1078 // subsequent cases.
1079 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1080 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001081 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001082
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001083 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001084 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001085 elms->set(WRITABLE_INDEX, heap->false_value());
1086 elms->set(ENUMERABLE_INDEX, heap->false_value());
1087 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001088 return *desc;
1089 }
1090
1091 case JSObject::INTERCEPTED_ELEMENT:
1092 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001093 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001094 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001095 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001096 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001097 elms->set(WRITABLE_INDEX, heap->true_value());
1098 elms->set(ENUMERABLE_INDEX, heap->true_value());
1099 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001100 return *desc;
1101 }
1102
1103 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001104 Handle<JSObject> holder = obj;
1105 if (obj->IsJSGlobalProxy()) {
1106 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001107 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001108 ASSERT(proto->IsJSGlobalObject());
1109 holder = Handle<JSObject>(JSObject::cast(proto));
1110 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001111 FixedArray* elements = FixedArray::cast(holder->elements());
1112 NumberDictionary* dictionary = NULL;
1113 if (elements->map() == heap->non_strict_arguments_elements_map()) {
1114 dictionary = NumberDictionary::cast(elements->get(1));
1115 } else {
1116 dictionary = NumberDictionary::cast(elements);
1117 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001118 int entry = dictionary->FindEntry(index);
1119 ASSERT(entry != NumberDictionary::kNotFound);
1120 PropertyDetails details = dictionary->DetailsAt(entry);
1121 switch (details.type()) {
1122 case CALLBACKS: {
1123 // This is an accessor property with getter and/or setter.
1124 FixedArray* callbacks =
1125 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001126 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001127 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
1128 elms->set(GETTER_INDEX, callbacks->get(0));
1129 }
1130 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
1131 elms->set(SETTER_INDEX, callbacks->get(1));
1132 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001133 break;
1134 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001135 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001136 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001137 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001138 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001139 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001140 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001141 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001142 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001143 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001144 default:
1145 UNREACHABLE();
1146 break;
1147 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001148 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1149 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001150 return *desc;
1151 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001152 }
1153 }
1154
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001155 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001156 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001157
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001158 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001159 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001160 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001161
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001162 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001163 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001164 }
1165
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001166 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1167 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001168
1169 bool is_js_accessor = (result.type() == CALLBACKS) &&
1170 (result.GetCallbackObject()->IsFixedArray());
1171
1172 if (is_js_accessor) {
1173 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001174 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001175
1176 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1177 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1178 elms->set(GETTER_INDEX, structure->get(0));
1179 }
1180 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1181 elms->set(SETTER_INDEX, structure->get(1));
1182 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001183 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001184 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1185 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001186
1187 PropertyAttributes attrs;
1188 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001189 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001190 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1191 if (!maybe_value->ToObject(&value)) return maybe_value;
1192 }
1193 elms->set(VALUE_INDEX, value);
1194 }
1195
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001196 return *desc;
1197}
1198
1199
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001200RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001201 ASSERT(args.length() == 1);
1202 CONVERT_CHECKED(JSObject, obj, args[0]);
1203 return obj->PreventExtensions();
1204}
1205
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001207RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001208 ASSERT(args.length() == 1);
1209 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001210 if (obj->IsJSGlobalProxy()) {
1211 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001212 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001213 ASSERT(proto->IsJSGlobalObject());
1214 obj = JSObject::cast(proto);
1215 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001216 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001217}
1218
1219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001220RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001221 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001223 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1224 CONVERT_ARG_CHECKED(String, pattern, 1);
1225 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001226 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1227 if (result.is_null()) return Failure::Exception();
1228 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001229}
1230
1231
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001232RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001233 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001235 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001236 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001237}
1238
1239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001240RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001241 ASSERT(args.length() == 1);
1242 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001243 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001244 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001245}
1246
1247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001248RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249 ASSERT(args.length() == 2);
1250 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001251 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001252 int index = field->value();
1253 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1254 InstanceType type = templ->map()->instance_type();
1255 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1256 type == OBJECT_TEMPLATE_INFO_TYPE);
1257 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001258 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001259 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1260 } else {
1261 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1262 }
1263 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001264}
1265
1266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001267RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001268 ASSERT(args.length() == 1);
1269 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001270 Map* old_map = object->map();
1271 bool needs_access_checks = old_map->is_access_check_needed();
1272 if (needs_access_checks) {
1273 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001274 Object* new_map;
1275 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1276 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1277 }
ager@chromium.org32912102009-01-16 10:38:43 +00001278
1279 Map::cast(new_map)->set_is_access_check_needed(false);
1280 object->set_map(Map::cast(new_map));
1281 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001282 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001283}
1284
1285
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001286RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001287 ASSERT(args.length() == 1);
1288 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001289 Map* old_map = object->map();
1290 if (!old_map->is_access_check_needed()) {
1291 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001292 Object* new_map;
1293 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1294 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1295 }
ager@chromium.org32912102009-01-16 10:38:43 +00001296
1297 Map::cast(new_map)->set_is_access_check_needed(true);
1298 object->set_map(Map::cast(new_map));
1299 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001300 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001301}
1302
1303
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001304static Failure* ThrowRedeclarationError(Isolate* isolate,
1305 const char* type,
1306 Handle<String> name) {
1307 HandleScope scope(isolate);
1308 Handle<Object> type_handle =
1309 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001310 Handle<Object> args[2] = { type_handle, name };
1311 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001312 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1313 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001314}
1315
1316
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001317RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001318 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001319 HandleScope scope(isolate);
1320 Handle<GlobalObject> global = Handle<GlobalObject>(
1321 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001322
ager@chromium.org3811b432009-10-28 14:53:37 +00001323 Handle<Context> context = args.at<Context>(0);
1324 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001325 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001326
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001327 // Traverse the name/value pairs and set the properties.
1328 int length = pairs->length();
1329 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001330 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001332 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001333
1334 // We have to declare a global const property. To capture we only
1335 // assign to it when evaluating the assignment for "const x =
1336 // <expr>" the initial value is the hole.
1337 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001338 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001339 if (value->IsUndefined() || is_const_property) {
1340 // Lookup the property in the global object, and don't set the
1341 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001342 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001343 global->Lookup(*name, &lookup);
1344 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001345 // We found an existing property. Unless it was an interceptor
1346 // that claims the property is absent, skip this declaration.
1347 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001348 continue;
1349 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001350 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1351 if (attributes != ABSENT) {
1352 continue;
1353 }
1354 // Fall-through and introduce the absent property by using
1355 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356 }
1357 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001358 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001359 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001360 Handle<SharedFunctionInfo> shared =
1361 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001362 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001363 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1364 context,
1365 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001366 value = function;
1367 }
1368
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001369 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001370 global->LocalLookup(*name, &lookup);
1371
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001372 // Compute the property attributes. According to ECMA-262, section
1373 // 13, page 71, the property must be read-only and
1374 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1375 // property as read-only, so we don't either.
1376 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001377 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001378 attr |= DONT_DELETE;
1379 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001380 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001381 if (is_const_property || (is_native && is_function_declaration)) {
1382 attr |= READ_ONLY;
1383 }
1384
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001385 // Safari does not allow the invocation of callback setters for
1386 // function declarations. To mimic this behavior, we do not allow
1387 // the invocation of setters for function values. This makes a
1388 // difference for global functions with the same names as event
1389 // handlers such as "function onload() {}". Firefox does call the
1390 // onload setter in those case and Safari does not. We follow
1391 // Safari for compatibility.
1392 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001393 // Do not change DONT_DELETE to false from true.
1394 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001395 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001396 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001397 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1398
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001399 RETURN_IF_EMPTY_HANDLE(isolate,
1400 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001401 name,
1402 value,
1403 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001404 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001405 StrictModeFlag strict_mode = DeclareGlobalsStrictModeFlag::decode(flags);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001406 RETURN_IF_EMPTY_HANDLE(isolate,
1407 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001408 name,
1409 value,
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001410 static_cast<PropertyAttributes>(attr),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001411 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001412 }
1413 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001414
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001415 ASSERT(!isolate->has_pending_exception());
1416 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001417}
1418
1419
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001420RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001421 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001422 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001423
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001424 // Declarations are always made in a function or global context. In the
1425 // case of eval code, the context passed is the context of the caller,
1426 // which may be some nested context and not the declaration context.
1427 RUNTIME_ASSERT(args[0]->IsContext());
1428 Handle<Context> context(Context::cast(args[0])->declaration_context());
1429
ager@chromium.org7c537e22008-10-16 08:43:32 +00001430 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001431 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001432 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001433 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001434
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001435 int index;
1436 PropertyAttributes attributes;
1437 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001438 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001439 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001440 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001441
1442 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001443 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001444 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1445 // Functions are not read-only.
1446 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1447 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001448 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001449 }
1450
1451 // Initialize it if necessary.
1452 if (*initial_value != NULL) {
1453 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001454 ASSERT(holder.is_identical_to(context));
1455 if (((attributes & READ_ONLY) == 0) ||
1456 context->get(index)->IsTheHole()) {
1457 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001458 }
1459 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001460 // Slow case: The property is in the context extension object of a
1461 // function context or the global object of a global context.
1462 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001463 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001464 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001465 SetProperty(object, name, initial_value, mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001466 }
1467 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001468
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001469 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001470 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001471 // "declared" in the function context's extension context or as a
1472 // property of the the global object.
1473 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001474 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001475 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001476 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001477 // Context extension objects are allocated lazily.
1478 ASSERT(context->IsFunctionContext());
1479 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001480 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001481 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001482 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001483 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001484
ager@chromium.org7c537e22008-10-16 08:43:32 +00001485 // Declare the property by setting it to the initial value if provided,
1486 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1487 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001488 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001489 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001490 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001491 // Declaring a const context slot is a conflicting declaration if
1492 // there is a callback with that name in a prototype. It is
1493 // allowed to introduce const variables in
1494 // JSContextExtensionObjects. They are treated specially in
1495 // SetProperty and no setters are invoked for those since they are
1496 // not real JSObjects.
1497 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001498 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001499 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001500 object->Lookup(*name, &lookup);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001501 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001502 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001503 }
1504 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001505 RETURN_IF_EMPTY_HANDLE(isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001506 SetProperty(object, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001507 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001508 }
1509
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001510 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001511}
1512
1513
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001514RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001516 // args[0] == name
1517 // args[1] == strict_mode
1518 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001519
1520 // Determine if we need to assign to the variable if it already
1521 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001522 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1523 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001524
1525 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001526 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001527 RUNTIME_ASSERT(args[1]->IsSmi());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001528 CONVERT_STRICT_MODE_ARG(strict_mode, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529
1530 // According to ECMA-262, section 12.2, page 62, the property must
1531 // not be deletable.
1532 PropertyAttributes attributes = DONT_DELETE;
1533
1534 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001535 // there, there is a property with this name in the prototype chain.
1536 // We follow Safari and Firefox behavior and only set the property
1537 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001538 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001539 // Note that objects can have hidden prototypes, so we need to traverse
1540 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001541 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001542 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001543 while (object->IsJSObject() &&
1544 JSObject::cast(object)->map()->is_hidden_prototype()) {
1545 JSObject* raw_holder = JSObject::cast(object);
1546 raw_holder->LocalLookup(*name, &lookup);
1547 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
1548 HandleScope handle_scope(isolate);
1549 Handle<JSObject> holder(raw_holder);
1550 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1551 // Update the raw pointer in case it's changed due to GC.
1552 raw_holder = *holder;
1553 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1554 // Found an interceptor that's not read only.
1555 if (assign) {
1556 return raw_holder->SetProperty(
1557 &lookup, *name, args[2], attributes, strict_mode);
1558 } else {
1559 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001560 }
1561 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001562 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001563 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564 }
1565
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001566 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001567 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001568 if (assign) {
1569 return global->SetProperty(*name, args[2], attributes, strict_mode);
1570 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001571 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001572}
1573
1574
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001575RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001576 // All constants are declared with an initial value. The name
1577 // of the constant is the first argument and the initial value
1578 // is the second.
1579 RUNTIME_ASSERT(args.length() == 2);
1580 CONVERT_ARG_CHECKED(String, name, 0);
1581 Handle<Object> value = args.at<Object>(1);
1582
1583 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001584 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001585
1586 // According to ECMA-262, section 12.2, page 62, the property must
1587 // not be deletable. Since it's a const, it must be READ_ONLY too.
1588 PropertyAttributes attributes =
1589 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1590
1591 // Lookup the property locally in the global object. If it isn't
1592 // there, we add the property and take special precautions to always
1593 // add it as a local property even in case of callbacks in the
1594 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001595 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001596 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001597 global->LocalLookup(*name, &lookup);
1598 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001599 return global->SetLocalPropertyIgnoreAttributes(*name,
1600 *value,
1601 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602 }
1603
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001604 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001606 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001607 HandleScope handle_scope(isolate);
1608 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001609
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001610 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001611 // property through an interceptor and only do it if it's
1612 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001613 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001614 RETURN_IF_EMPTY_HANDLE(isolate,
1615 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001616 name,
1617 value,
1618 attributes,
1619 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001620 return *value;
1621 }
1622
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001623 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001624 // constant. For now, we determine this by checking if the
1625 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001626 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001627 PropertyType type = lookup.type();
1628 if (type == FIELD) {
1629 FixedArray* properties = global->properties();
1630 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001631 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001632 properties->set(index, *value);
1633 }
1634 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001635 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1636 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001637 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001638 }
1639 } else {
1640 // Ignore re-initialization of constants that have already been
1641 // assigned a function value.
1642 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1643 }
1644
1645 // Use the set value as the result of the operation.
1646 return *value;
1647}
1648
1649
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001650RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001651 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001652 ASSERT(args.length() == 3);
1653
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001654 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001655 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001656
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001657 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001658 RUNTIME_ASSERT(args[1]->IsContext());
1659 Handle<Context> context(Context::cast(args[1])->declaration_context());
1660
1661 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001662
1663 int index;
1664 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001665 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001666 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001667 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001668 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001669
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001670 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001671 ASSERT(holder->IsContext());
1672 // Property was found in a context. Perform the assignment if we
1673 // found some non-constant or an uninitialized constant.
1674 Handle<Context> context = Handle<Context>::cast(holder);
1675 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1676 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001677 }
1678 return *value;
1679 }
1680
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001681 // The property could not be found, we introduce it as a property of the
1682 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001683 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001684 Handle<JSObject> global = Handle<JSObject>(
1685 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001686 // Strict mode not needed (const disallowed in strict mode).
1687 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001688 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001689 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001690 return *value;
1691 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001692
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001693 // The property was present in some function's context extension object,
1694 // as a property on the subject of a with, or as a property of the global
1695 // object.
1696 //
1697 // In most situations, eval-introduced consts should still be present in
1698 // the context extension object. However, because declaration and
1699 // initialization are separate, the property might have been deleted
1700 // before we reach the initialization point.
1701 //
1702 // Example:
1703 //
1704 // function f() { eval("delete x; const x;"); }
1705 //
1706 // In that case, the initialization behaves like a normal assignment.
1707 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001708
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001709 if (*object == context->extension()) {
1710 // This is the property that was introduced by the const declaration.
1711 // Set it if it hasn't been set before. NOTE: We cannot use
1712 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001713 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001714 object->LocalLookupRealNamedProperty(*name, &lookup);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001715 ASSERT(lookup.IsProperty()); // the property was declared
1716 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1717
1718 PropertyType type = lookup.type();
1719 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001720 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001721 int index = lookup.GetFieldIndex();
1722 if (properties->get(index)->IsTheHole()) {
1723 properties->set(index, *value);
1724 }
1725 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001726 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1727 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001728 }
1729 } else {
1730 // We should not reach here. Any real, named property should be
1731 // either a field or a dictionary slot.
1732 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001733 }
1734 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001735 // The property was found on some other object. Set it if it is not a
1736 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001737 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001738 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001739 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001740 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001741 SetProperty(object, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001742 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001743 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001744
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001745 return *value;
1746}
1747
1748
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001749RUNTIME_FUNCTION(MaybeObject*,
1750 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001752 ASSERT(args.length() == 2);
1753 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001754 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001755 if (object->HasFastProperties()) {
1756 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1757 }
1758 return *object;
1759}
1760
1761
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001762RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001764 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001765 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1766 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001767 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001768 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001769 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001770 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001771 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001772 RUNTIME_ASSERT(index >= 0);
1773 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001774 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001775 Handle<Object> result = RegExpImpl::Exec(regexp,
1776 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001777 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001778 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001779 if (result.is_null()) return Failure::Exception();
1780 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001781}
1782
1783
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001784RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001785 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001786 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001787 if (elements_count < 0 ||
1788 elements_count > FixedArray::kMaxLength ||
1789 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001790 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001791 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001792 Object* new_object;
1793 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001794 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001795 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1796 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001797 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1799 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001800 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1801 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001802 {
1803 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001804 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001805 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001806 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001807 }
1808 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001809 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001810 array->set_elements(elements);
1811 array->set_length(Smi::FromInt(elements_count));
1812 // Write in-object properties after the length of the array.
1813 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1814 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1815 return array;
1816}
1817
1818
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001819RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001820 AssertNoAllocation no_alloc;
1821 ASSERT(args.length() == 5);
1822 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1823 CONVERT_CHECKED(String, source, args[1]);
1824
1825 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001826 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001827
1828 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001829 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001830
1831 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001832 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001833
1834 Map* map = regexp->map();
1835 Object* constructor = map->constructor();
1836 if (constructor->IsJSFunction() &&
1837 JSFunction::cast(constructor)->initial_map() == map) {
1838 // If we still have the original map, set in-object properties directly.
1839 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1840 // TODO(lrn): Consider skipping write barrier on booleans as well.
1841 // Both true and false should be in oldspace at all times.
1842 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1843 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1844 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1845 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1846 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001847 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001848 return regexp;
1849 }
1850
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001851 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001852 PropertyAttributes final =
1853 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1854 PropertyAttributes writable =
1855 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001856 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001857 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001858 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001859 source,
1860 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001861 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001862 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001863 global,
1864 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001865 ASSERT(!result->IsFailure());
1866 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001867 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001868 ignoreCase,
1869 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001870 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001871 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001872 multiline,
1873 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001874 ASSERT(!result->IsFailure());
1875 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001876 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001877 Smi::FromInt(0),
1878 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001879 ASSERT(!result->IsFailure());
1880 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001881 return regexp;
1882}
1883
1884
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001885RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001886 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001887 ASSERT(args.length() == 1);
1888 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1889 // This is necessary to enable fast checks for absence of elements
1890 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001891 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001892 return Smi::FromInt(0);
1893}
1894
1895
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001896static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1897 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001898 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001899 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001900 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1901 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1902 Handle<JSFunction> optimized =
1903 isolate->factory()->NewFunction(key,
1904 JS_OBJECT_TYPE,
1905 JSObject::kHeaderSize,
1906 code,
1907 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001908 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001909 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001910 return optimized;
1911}
1912
1913
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001914RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001915 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001916 ASSERT(args.length() == 1);
1917 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1918
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001919 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1920 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1921 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1922 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1923 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1924 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1925 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001926
1927 return *holder;
1928}
1929
1930
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001931RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1932 NoHandleAllocation handle_free;
1933 ASSERT(args.length() == 1);
1934 CONVERT_CHECKED(JSFunction, function, args[0]);
1935 SharedFunctionInfo* shared = function->shared();
1936 if (shared->native() || shared->strict_mode()) {
1937 return isolate->heap()->undefined_value();
1938 }
1939 // Returns undefined for strict or native functions, or
1940 // the associated global receiver for "normal" functions.
1941
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001942 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001943 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001944 return global_context->global()->global_receiver();
1945}
1946
1947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001948RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001949 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001950 ASSERT(args.length() == 4);
1951 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001952 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001953 Handle<String> pattern = args.at<String>(2);
1954 Handle<String> flags = args.at<String>(3);
1955
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001956 // Get the RegExp function from the context in the literals array.
1957 // This is the RegExp function from the context in which the
1958 // function was created. We do not use the RegExp function from the
1959 // current global context because this might be the RegExp function
1960 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001961 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001962 Handle<JSFunction>(
1963 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001964 // Compute the regular expression literal.
1965 bool has_pending_exception;
1966 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001967 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1968 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001969 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001970 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001971 return Failure::Exception();
1972 }
1973 literals->set(index, *regexp);
1974 return *regexp;
1975}
1976
1977
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001978RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001979 NoHandleAllocation ha;
1980 ASSERT(args.length() == 1);
1981
1982 CONVERT_CHECKED(JSFunction, f, args[0]);
1983 return f->shared()->name();
1984}
1985
1986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001987RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001988 NoHandleAllocation ha;
1989 ASSERT(args.length() == 2);
1990
1991 CONVERT_CHECKED(JSFunction, f, args[0]);
1992 CONVERT_CHECKED(String, name, args[1]);
1993 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001994 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001995}
1996
1997
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001998RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1999 NoHandleAllocation ha;
2000 ASSERT(args.length() == 1);
2001 CONVERT_CHECKED(JSFunction, f, args[0]);
2002 return isolate->heap()->ToBoolean(
2003 f->shared()->name_should_print_as_anonymous());
2004}
2005
2006
2007RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
2008 NoHandleAllocation ha;
2009 ASSERT(args.length() == 1);
2010 CONVERT_CHECKED(JSFunction, f, args[0]);
2011 f->shared()->set_name_should_print_as_anonymous(true);
2012 return isolate->heap()->undefined_value();
2013}
2014
2015
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002016RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002017 NoHandleAllocation ha;
2018 ASSERT(args.length() == 1);
2019
2020 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002021 Object* obj = f->RemovePrototype();
2022 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002023
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002024 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002025}
2026
2027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002028RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002029 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002030 ASSERT(args.length() == 1);
2031
2032 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002033 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2034 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002035
2036 return *GetScriptWrapper(Handle<Script>::cast(script));
2037}
2038
2039
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002040RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002041 NoHandleAllocation ha;
2042 ASSERT(args.length() == 1);
2043
2044 CONVERT_CHECKED(JSFunction, f, args[0]);
2045 return f->shared()->GetSourceCode();
2046}
2047
2048
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002049RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002050 NoHandleAllocation ha;
2051 ASSERT(args.length() == 1);
2052
2053 CONVERT_CHECKED(JSFunction, fun, args[0]);
2054 int pos = fun->shared()->start_position();
2055 return Smi::FromInt(pos);
2056}
2057
2058
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002059RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002060 ASSERT(args.length() == 2);
2061
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002062 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002063 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2064
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002065 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2066
2067 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002068 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002069}
2070
2071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002072RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002073 NoHandleAllocation ha;
2074 ASSERT(args.length() == 2);
2075
2076 CONVERT_CHECKED(JSFunction, fun, args[0]);
2077 CONVERT_CHECKED(String, name, args[1]);
2078 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002079 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002080}
2081
2082
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002083RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002084 NoHandleAllocation ha;
2085 ASSERT(args.length() == 2);
2086
2087 CONVERT_CHECKED(JSFunction, fun, args[0]);
2088 CONVERT_CHECKED(Smi, length, args[1]);
2089 fun->shared()->set_length(length->value());
2090 return length;
2091}
2092
2093
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002094RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002095 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002096 ASSERT(args.length() == 2);
2097
2098 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002099 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002100 Object* obj;
2101 { MaybeObject* maybe_obj =
2102 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2103 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2104 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002105 return args[0]; // return TOS
2106}
2107
2108
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002109RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2110 NoHandleAllocation ha;
2111 RUNTIME_ASSERT(args.length() == 1);
2112 CONVERT_CHECKED(JSFunction, function, args[0]);
2113
2114 MaybeObject* maybe_name =
2115 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2116 String* name;
2117 if (!maybe_name->To(&name)) return maybe_name;
2118
2119 if (function->HasFastProperties()) {
2120 // Construct a new field descriptor with updated attributes.
2121 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2122 int index = instance_desc->Search(name);
2123 ASSERT(index != DescriptorArray::kNotFound);
2124 PropertyDetails details(instance_desc->GetDetails(index));
2125 CallbacksDescriptor new_desc(name,
2126 instance_desc->GetValue(index),
2127 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2128 details.index());
2129 // Construct a new field descriptors array containing the new descriptor.
2130 Object* descriptors_unchecked;
2131 { MaybeObject* maybe_descriptors_unchecked =
2132 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2133 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2134 return maybe_descriptors_unchecked;
2135 }
2136 }
2137 DescriptorArray* new_descriptors =
2138 DescriptorArray::cast(descriptors_unchecked);
2139 // Create a new map featuring the new field descriptors array.
2140 Object* map_unchecked;
2141 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2142 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2143 return maybe_map_unchecked;
2144 }
2145 }
2146 Map* new_map = Map::cast(map_unchecked);
2147 new_map->set_instance_descriptors(new_descriptors);
2148 function->set_map(new_map);
2149 } else { // Dictionary properties.
2150 // Directly manipulate the property details.
2151 int entry = function->property_dictionary()->FindEntry(name);
2152 ASSERT(entry != StringDictionary::kNotFound);
2153 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2154 PropertyDetails new_details(
2155 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2156 details.type(),
2157 details.index());
2158 function->property_dictionary()->DetailsAtPut(entry, new_details);
2159 }
2160 return function;
2161}
2162
2163
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002164RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002165 NoHandleAllocation ha;
2166 ASSERT(args.length() == 1);
2167
2168 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002169 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002170}
2171
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002172
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002173RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002174 NoHandleAllocation ha;
2175 ASSERT(args.length() == 1);
2176
2177 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002178 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002179}
2180
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002181
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002182RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002183 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002184 ASSERT(args.length() == 2);
2185
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002186 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002187 Handle<Object> code = args.at<Object>(1);
2188
2189 Handle<Context> context(target->context());
2190
2191 if (!code->IsNull()) {
2192 RUNTIME_ASSERT(code->IsJSFunction());
2193 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002194 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002195
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002196 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002197 return Failure::Exception();
2198 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002199 // Since we don't store the source for this we should never
2200 // optimize this.
2201 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002202 // Set the code, scope info, formal parameter count,
2203 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002204 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002205 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002206 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002207 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002208 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002209 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002210 // Set the source code of the target function to undefined.
2211 // SetCode is only used for built-in constructors like String,
2212 // Array, and Object, and some web code
2213 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002214 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002215 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002216 // Clear the optimization hints related to the compiled code as these are no
2217 // longer valid when the code is overwritten.
2218 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002219 context = Handle<Context>(fun->context());
2220
2221 // Make sure we get a fresh copy of the literal vector to avoid
2222 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002223 int number_of_literals = fun->NumberOfLiterals();
2224 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002225 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002226 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002227 // Insert the object, regexp and array functions in the literals
2228 // array prefix. These are the functions that will be used when
2229 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002230 literals->set(JSFunction::kLiteralGlobalContextIndex,
2231 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002232 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002233 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002234 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002235
2236 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2237 isolate->logger()->LogExistingFunction(
2238 shared, Handle<Code>(shared->code()));
2239 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002240 }
2241
2242 target->set_context(*context);
2243 return *target;
2244}
2245
2246
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002247RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002248 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002249 ASSERT(args.length() == 2);
2250 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002251 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002252 RUNTIME_ASSERT(num >= 0);
2253 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002254 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002255}
2256
2257
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002258MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2259 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002260 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002261 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002262 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002263 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002264 }
2265 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002266 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002267}
2268
2269
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002270RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002271 NoHandleAllocation ha;
2272 ASSERT(args.length() == 2);
2273
2274 CONVERT_CHECKED(String, subject, args[0]);
2275 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002276 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002277
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002278 uint32_t i = 0;
2279 if (index->IsSmi()) {
2280 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002281 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002282 i = value;
2283 } else {
2284 ASSERT(index->IsHeapNumber());
2285 double value = HeapNumber::cast(index)->value();
2286 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002287 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002288
2289 // Flatten the string. If someone wants to get a char at an index
2290 // in a cons string, it is likely that more indices will be
2291 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002292 Object* flat;
2293 { MaybeObject* maybe_flat = subject->TryFlatten();
2294 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2295 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002296 subject = String::cast(flat);
2297
2298 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002299 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002300 }
2301
2302 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002303}
2304
2305
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002306RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002307 NoHandleAllocation ha;
2308 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002309 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002310}
2311
lrn@chromium.org25156de2010-04-06 13:10:27 +00002312
2313class FixedArrayBuilder {
2314 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002315 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2316 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002317 length_(0),
2318 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002319 // Require a non-zero initial size. Ensures that doubling the size to
2320 // extend the array will work.
2321 ASSERT(initial_capacity > 0);
2322 }
2323
2324 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2325 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002326 length_(0),
2327 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002328 // Require a non-zero initial size. Ensures that doubling the size to
2329 // extend the array will work.
2330 ASSERT(backing_store->length() > 0);
2331 }
2332
2333 bool HasCapacity(int elements) {
2334 int length = array_->length();
2335 int required_length = length_ + elements;
2336 return (length >= required_length);
2337 }
2338
2339 void EnsureCapacity(int elements) {
2340 int length = array_->length();
2341 int required_length = length_ + elements;
2342 if (length < required_length) {
2343 int new_length = length;
2344 do {
2345 new_length *= 2;
2346 } while (new_length < required_length);
2347 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002348 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002349 array_->CopyTo(0, *extended_array, 0, length_);
2350 array_ = extended_array;
2351 }
2352 }
2353
2354 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002355 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002356 ASSERT(length_ < capacity());
2357 array_->set(length_, value);
2358 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002359 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002360 }
2361
2362 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002363 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002364 ASSERT(length_ < capacity());
2365 array_->set(length_, value);
2366 length_++;
2367 }
2368
2369 Handle<FixedArray> array() {
2370 return array_;
2371 }
2372
2373 int length() {
2374 return length_;
2375 }
2376
2377 int capacity() {
2378 return array_->length();
2379 }
2380
2381 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002382 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002383 result_array->set_length(Smi::FromInt(length_));
2384 return result_array;
2385 }
2386
2387 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002388 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002389 target_array->set_length(Smi::FromInt(length_));
2390 return target_array;
2391 }
2392
2393 private:
2394 Handle<FixedArray> array_;
2395 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002396 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002397};
2398
2399
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002400// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002401const int kStringBuilderConcatHelperLengthBits = 11;
2402const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002403
2404template <typename schar>
2405static inline void StringBuilderConcatHelper(String*,
2406 schar*,
2407 FixedArray*,
2408 int);
2409
lrn@chromium.org25156de2010-04-06 13:10:27 +00002410typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2411 StringBuilderSubstringLength;
2412typedef BitField<int,
2413 kStringBuilderConcatHelperLengthBits,
2414 kStringBuilderConcatHelperPositionBits>
2415 StringBuilderSubstringPosition;
2416
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002417
2418class ReplacementStringBuilder {
2419 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002420 ReplacementStringBuilder(Heap* heap,
2421 Handle<String> subject,
2422 int estimated_part_count)
2423 : heap_(heap),
2424 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002425 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002426 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002427 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002428 // Require a non-zero initial size. Ensures that doubling the size to
2429 // extend the array will work.
2430 ASSERT(estimated_part_count > 0);
2431 }
2432
lrn@chromium.org25156de2010-04-06 13:10:27 +00002433 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2434 int from,
2435 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002436 ASSERT(from >= 0);
2437 int length = to - from;
2438 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002439 if (StringBuilderSubstringLength::is_valid(length) &&
2440 StringBuilderSubstringPosition::is_valid(from)) {
2441 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2442 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002443 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002444 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002445 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002446 builder->Add(Smi::FromInt(-length));
2447 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002448 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002449 }
2450
2451
2452 void EnsureCapacity(int elements) {
2453 array_builder_.EnsureCapacity(elements);
2454 }
2455
2456
2457 void AddSubjectSlice(int from, int to) {
2458 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002459 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002460 }
2461
2462
2463 void AddString(Handle<String> string) {
2464 int length = string->length();
2465 ASSERT(length > 0);
2466 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002467 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002468 is_ascii_ = false;
2469 }
2470 IncrementCharacterCount(length);
2471 }
2472
2473
2474 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002475 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002476 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002477 }
2478
2479 Handle<String> joined_string;
2480 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002481 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002482 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002483 char* char_buffer = seq->GetChars();
2484 StringBuilderConcatHelper(*subject_,
2485 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002486 *array_builder_.array(),
2487 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002488 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002489 } else {
2490 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002491 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002492 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002493 uc16* char_buffer = seq->GetChars();
2494 StringBuilderConcatHelper(*subject_,
2495 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002496 *array_builder_.array(),
2497 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002498 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002499 }
2500 return joined_string;
2501 }
2502
2503
2504 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002505 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002506 V8::FatalProcessOutOfMemory("String.replace result too large.");
2507 }
2508 character_count_ += by;
2509 }
2510
lrn@chromium.org25156de2010-04-06 13:10:27 +00002511 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002512 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002513 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002514
lrn@chromium.org25156de2010-04-06 13:10:27 +00002515 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002516 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2517 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002518 }
2519
2520
ager@chromium.org04921a82011-06-27 13:21:41 +00002521 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2522 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002523 }
2524
2525
2526 void AddElement(Object* element) {
2527 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002528 ASSERT(array_builder_.capacity() > array_builder_.length());
2529 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002530 }
2531
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002532 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002533 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002534 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002535 int character_count_;
2536 bool is_ascii_;
2537};
2538
2539
2540class CompiledReplacement {
2541 public:
2542 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002543 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002544
2545 void Compile(Handle<String> replacement,
2546 int capture_count,
2547 int subject_length);
2548
2549 void Apply(ReplacementStringBuilder* builder,
2550 int match_from,
2551 int match_to,
2552 Handle<JSArray> last_match_info);
2553
2554 // Number of distinct parts of the replacement pattern.
2555 int parts() {
2556 return parts_.length();
2557 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002558
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002559 bool simple_hint() {
2560 return simple_hint_;
2561 }
2562
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002563 private:
2564 enum PartType {
2565 SUBJECT_PREFIX = 1,
2566 SUBJECT_SUFFIX,
2567 SUBJECT_CAPTURE,
2568 REPLACEMENT_SUBSTRING,
2569 REPLACEMENT_STRING,
2570
2571 NUMBER_OF_PART_TYPES
2572 };
2573
2574 struct ReplacementPart {
2575 static inline ReplacementPart SubjectMatch() {
2576 return ReplacementPart(SUBJECT_CAPTURE, 0);
2577 }
2578 static inline ReplacementPart SubjectCapture(int capture_index) {
2579 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2580 }
2581 static inline ReplacementPart SubjectPrefix() {
2582 return ReplacementPart(SUBJECT_PREFIX, 0);
2583 }
2584 static inline ReplacementPart SubjectSuffix(int subject_length) {
2585 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2586 }
2587 static inline ReplacementPart ReplacementString() {
2588 return ReplacementPart(REPLACEMENT_STRING, 0);
2589 }
2590 static inline ReplacementPart ReplacementSubString(int from, int to) {
2591 ASSERT(from >= 0);
2592 ASSERT(to > from);
2593 return ReplacementPart(-from, to);
2594 }
2595
2596 // If tag <= 0 then it is the negation of a start index of a substring of
2597 // the replacement pattern, otherwise it's a value from PartType.
2598 ReplacementPart(int tag, int data)
2599 : tag(tag), data(data) {
2600 // Must be non-positive or a PartType value.
2601 ASSERT(tag < NUMBER_OF_PART_TYPES);
2602 }
2603 // Either a value of PartType or a non-positive number that is
2604 // the negation of an index into the replacement string.
2605 int tag;
2606 // The data value's interpretation depends on the value of tag:
2607 // tag == SUBJECT_PREFIX ||
2608 // tag == SUBJECT_SUFFIX: data is unused.
2609 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2610 // tag == REPLACEMENT_SUBSTRING ||
2611 // tag == REPLACEMENT_STRING: data is index into array of substrings
2612 // of the replacement string.
2613 // tag <= 0: Temporary representation of the substring of the replacement
2614 // string ranging over -tag .. data.
2615 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2616 // substring objects.
2617 int data;
2618 };
2619
2620 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002621 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002622 Vector<Char> characters,
2623 int capture_count,
2624 int subject_length) {
2625 int length = characters.length();
2626 int last = 0;
2627 for (int i = 0; i < length; i++) {
2628 Char c = characters[i];
2629 if (c == '$') {
2630 int next_index = i + 1;
2631 if (next_index == length) { // No next character!
2632 break;
2633 }
2634 Char c2 = characters[next_index];
2635 switch (c2) {
2636 case '$':
2637 if (i > last) {
2638 // There is a substring before. Include the first "$".
2639 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2640 last = next_index + 1; // Continue after the second "$".
2641 } else {
2642 // Let the next substring start with the second "$".
2643 last = next_index;
2644 }
2645 i = next_index;
2646 break;
2647 case '`':
2648 if (i > last) {
2649 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2650 }
2651 parts->Add(ReplacementPart::SubjectPrefix());
2652 i = next_index;
2653 last = i + 1;
2654 break;
2655 case '\'':
2656 if (i > last) {
2657 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2658 }
2659 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2660 i = next_index;
2661 last = i + 1;
2662 break;
2663 case '&':
2664 if (i > last) {
2665 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2666 }
2667 parts->Add(ReplacementPart::SubjectMatch());
2668 i = next_index;
2669 last = i + 1;
2670 break;
2671 case '0':
2672 case '1':
2673 case '2':
2674 case '3':
2675 case '4':
2676 case '5':
2677 case '6':
2678 case '7':
2679 case '8':
2680 case '9': {
2681 int capture_ref = c2 - '0';
2682 if (capture_ref > capture_count) {
2683 i = next_index;
2684 continue;
2685 }
2686 int second_digit_index = next_index + 1;
2687 if (second_digit_index < length) {
2688 // Peek ahead to see if we have two digits.
2689 Char c3 = characters[second_digit_index];
2690 if ('0' <= c3 && c3 <= '9') { // Double digits.
2691 int double_digit_ref = capture_ref * 10 + c3 - '0';
2692 if (double_digit_ref <= capture_count) {
2693 next_index = second_digit_index;
2694 capture_ref = double_digit_ref;
2695 }
2696 }
2697 }
2698 if (capture_ref > 0) {
2699 if (i > last) {
2700 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2701 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002702 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002703 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2704 last = next_index + 1;
2705 }
2706 i = next_index;
2707 break;
2708 }
2709 default:
2710 i = next_index;
2711 break;
2712 }
2713 }
2714 }
2715 if (length > last) {
2716 if (last == 0) {
2717 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002718 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002719 } else {
2720 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2721 }
2722 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002723 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002724 }
2725
2726 ZoneList<ReplacementPart> parts_;
2727 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002728 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002729};
2730
2731
2732void CompiledReplacement::Compile(Handle<String> replacement,
2733 int capture_count,
2734 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002735 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002736 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002737 String::FlatContent content = replacement->GetFlatContent();
2738 ASSERT(content.IsFlat());
2739 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002740 simple_hint_ = ParseReplacementPattern(&parts_,
2741 content.ToAsciiVector(),
2742 capture_count,
2743 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002744 } else {
2745 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002746 simple_hint_ = ParseReplacementPattern(&parts_,
2747 content.ToUC16Vector(),
2748 capture_count,
2749 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002750 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002751 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002752 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002753 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002754 int substring_index = 0;
2755 for (int i = 0, n = parts_.length(); i < n; i++) {
2756 int tag = parts_[i].tag;
2757 if (tag <= 0) { // A replacement string slice.
2758 int from = -tag;
2759 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002760 replacement_substrings_.Add(
2761 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002762 parts_[i].tag = REPLACEMENT_SUBSTRING;
2763 parts_[i].data = substring_index;
2764 substring_index++;
2765 } else if (tag == REPLACEMENT_STRING) {
2766 replacement_substrings_.Add(replacement);
2767 parts_[i].data = substring_index;
2768 substring_index++;
2769 }
2770 }
2771}
2772
2773
2774void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2775 int match_from,
2776 int match_to,
2777 Handle<JSArray> last_match_info) {
2778 for (int i = 0, n = parts_.length(); i < n; i++) {
2779 ReplacementPart part = parts_[i];
2780 switch (part.tag) {
2781 case SUBJECT_PREFIX:
2782 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2783 break;
2784 case SUBJECT_SUFFIX: {
2785 int subject_length = part.data;
2786 if (match_to < subject_length) {
2787 builder->AddSubjectSlice(match_to, subject_length);
2788 }
2789 break;
2790 }
2791 case SUBJECT_CAPTURE: {
2792 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002793 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002794 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2795 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2796 if (from >= 0 && to > from) {
2797 builder->AddSubjectSlice(from, to);
2798 }
2799 break;
2800 }
2801 case REPLACEMENT_SUBSTRING:
2802 case REPLACEMENT_STRING:
2803 builder->AddString(replacement_substrings_[part.data]);
2804 break;
2805 default:
2806 UNREACHABLE();
2807 }
2808 }
2809}
2810
2811
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002812void FindAsciiStringIndices(Vector<const char> subject,
2813 char pattern,
2814 ZoneList<int>* indices,
2815 unsigned int limit) {
2816 ASSERT(limit > 0);
2817 // Collect indices of pattern in subject using memchr.
2818 // Stop after finding at most limit values.
2819 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2820 const char* subject_end = subject_start + subject.length();
2821 const char* pos = subject_start;
2822 while (limit > 0) {
2823 pos = reinterpret_cast<const char*>(
2824 memchr(pos, pattern, subject_end - pos));
2825 if (pos == NULL) return;
2826 indices->Add(static_cast<int>(pos - subject_start));
2827 pos++;
2828 limit--;
2829 }
2830}
2831
2832
2833template <typename SubjectChar, typename PatternChar>
2834void FindStringIndices(Isolate* isolate,
2835 Vector<const SubjectChar> subject,
2836 Vector<const PatternChar> pattern,
2837 ZoneList<int>* indices,
2838 unsigned int limit) {
2839 ASSERT(limit > 0);
2840 // Collect indices of pattern in subject.
2841 // Stop after finding at most limit values.
2842 int pattern_length = pattern.length();
2843 int index = 0;
2844 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2845 while (limit > 0) {
2846 index = search.Search(subject, index);
2847 if (index < 0) return;
2848 indices->Add(index);
2849 index += pattern_length;
2850 limit--;
2851 }
2852}
2853
2854
2855void FindStringIndicesDispatch(Isolate* isolate,
2856 String* subject,
2857 String* pattern,
2858 ZoneList<int>* indices,
2859 unsigned int limit) {
2860 {
2861 AssertNoAllocation no_gc;
2862 String::FlatContent subject_content = subject->GetFlatContent();
2863 String::FlatContent pattern_content = pattern->GetFlatContent();
2864 ASSERT(subject_content.IsFlat());
2865 ASSERT(pattern_content.IsFlat());
2866 if (subject_content.IsAscii()) {
2867 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2868 if (pattern_content.IsAscii()) {
2869 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2870 if (pattern_vector.length() == 1) {
2871 FindAsciiStringIndices(subject_vector,
2872 pattern_vector[0],
2873 indices,
2874 limit);
2875 } else {
2876 FindStringIndices(isolate,
2877 subject_vector,
2878 pattern_vector,
2879 indices,
2880 limit);
2881 }
2882 } else {
2883 FindStringIndices(isolate,
2884 subject_vector,
2885 pattern_content.ToUC16Vector(),
2886 indices,
2887 limit);
2888 }
2889 } else {
2890 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002891 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002892 FindStringIndices(isolate,
2893 subject_vector,
2894 pattern_content.ToAsciiVector(),
2895 indices,
2896 limit);
2897 } else {
2898 FindStringIndices(isolate,
2899 subject_vector,
2900 pattern_content.ToUC16Vector(),
2901 indices,
2902 limit);
2903 }
2904 }
2905 }
2906}
2907
2908
2909template<typename ResultSeqString>
2910MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2911 Isolate* isolate,
2912 Handle<String> subject,
2913 Handle<JSRegExp> pattern_regexp,
2914 Handle<String> replacement) {
2915 ASSERT(subject->IsFlat());
2916 ASSERT(replacement->IsFlat());
2917
2918 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2919 ZoneList<int> indices(8);
2920 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2921 String* pattern =
2922 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2923 int subject_len = subject->length();
2924 int pattern_len = pattern->length();
2925 int replacement_len = replacement->length();
2926
2927 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2928
2929 int matches = indices.length();
2930 if (matches == 0) return *subject;
2931
2932 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2933 int subject_pos = 0;
2934 int result_pos = 0;
2935
2936 Handle<ResultSeqString> result;
2937 if (ResultSeqString::kHasAsciiEncoding) {
2938 result = Handle<ResultSeqString>::cast(
2939 isolate->factory()->NewRawAsciiString(result_len));
2940 } else {
2941 result = Handle<ResultSeqString>::cast(
2942 isolate->factory()->NewRawTwoByteString(result_len));
2943 }
2944
2945 for (int i = 0; i < matches; i++) {
2946 // Copy non-matched subject content.
2947 if (subject_pos < indices.at(i)) {
2948 String::WriteToFlat(*subject,
2949 result->GetChars() + result_pos,
2950 subject_pos,
2951 indices.at(i));
2952 result_pos += indices.at(i) - subject_pos;
2953 }
2954
2955 // Replace match.
2956 if (replacement_len > 0) {
2957 String::WriteToFlat(*replacement,
2958 result->GetChars() + result_pos,
2959 0,
2960 replacement_len);
2961 result_pos += replacement_len;
2962 }
2963
2964 subject_pos = indices.at(i) + pattern_len;
2965 }
2966 // Add remaining subject content at the end.
2967 if (subject_pos < subject_len) {
2968 String::WriteToFlat(*subject,
2969 result->GetChars() + result_pos,
2970 subject_pos,
2971 subject_len);
2972 }
2973 return *result;
2974}
2975
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002976
lrn@chromium.org303ada72010-10-27 09:33:13 +00002977MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002978 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002979 String* subject,
2980 JSRegExp* regexp,
2981 String* replacement,
2982 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002983 ASSERT(subject->IsFlat());
2984 ASSERT(replacement->IsFlat());
2985
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002986 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002987
2988 int length = subject->length();
2989 Handle<String> subject_handle(subject);
2990 Handle<JSRegExp> regexp_handle(regexp);
2991 Handle<String> replacement_handle(replacement);
2992 Handle<JSArray> last_match_info_handle(last_match_info);
2993 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2994 subject_handle,
2995 0,
2996 last_match_info_handle);
2997 if (match.is_null()) {
2998 return Failure::Exception();
2999 }
3000 if (match->IsNull()) {
3001 return *subject_handle;
3002 }
3003
3004 int capture_count = regexp_handle->CaptureCount();
3005
3006 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003007 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003008 CompiledReplacement compiled_replacement;
3009 compiled_replacement.Compile(replacement_handle,
3010 capture_count,
3011 length);
3012
3013 bool is_global = regexp_handle->GetFlags().is_global();
3014
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003015 // Shortcut for simple non-regexp global replacements
3016 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003017 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003018 compiled_replacement.simple_hint()) {
3019 if (subject_handle->HasOnlyAsciiChars() &&
3020 replacement_handle->HasOnlyAsciiChars()) {
3021 return StringReplaceStringWithString<SeqAsciiString>(
3022 isolate, subject_handle, regexp_handle, replacement_handle);
3023 } else {
3024 return StringReplaceStringWithString<SeqTwoByteString>(
3025 isolate, subject_handle, regexp_handle, replacement_handle);
3026 }
3027 }
3028
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003029 // Guessing the number of parts that the final result string is built
3030 // from. Global regexps can match any number of times, so we guess
3031 // conservatively.
3032 int expected_parts =
3033 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003034 ReplacementStringBuilder builder(isolate->heap(),
3035 subject_handle,
3036 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003037
3038 // Index of end of last match.
3039 int prev = 0;
3040
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003041 // Number of parts added by compiled replacement plus preceeding
3042 // string and possibly suffix after last match. It is possible for
3043 // all components to use two elements when encoded as two smis.
3044 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003045 bool matched = true;
3046 do {
3047 ASSERT(last_match_info_handle->HasFastElements());
3048 // Increase the capacity of the builder before entering local handle-scope,
3049 // so its internal buffer can safely allocate a new handle if it grows.
3050 builder.EnsureCapacity(parts_added_per_loop);
3051
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003052 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003053 int start, end;
3054 {
3055 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003056 FixedArray* match_info_array =
3057 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003058
3059 ASSERT_EQ(capture_count * 2 + 2,
3060 RegExpImpl::GetLastCaptureCount(match_info_array));
3061 start = RegExpImpl::GetCapture(match_info_array, 0);
3062 end = RegExpImpl::GetCapture(match_info_array, 1);
3063 }
3064
3065 if (prev < start) {
3066 builder.AddSubjectSlice(prev, start);
3067 }
3068 compiled_replacement.Apply(&builder,
3069 start,
3070 end,
3071 last_match_info_handle);
3072 prev = end;
3073
3074 // Only continue checking for global regexps.
3075 if (!is_global) break;
3076
3077 // Continue from where the match ended, unless it was an empty match.
3078 int next = end;
3079 if (start == end) {
3080 next = end + 1;
3081 if (next > length) break;
3082 }
3083
3084 match = RegExpImpl::Exec(regexp_handle,
3085 subject_handle,
3086 next,
3087 last_match_info_handle);
3088 if (match.is_null()) {
3089 return Failure::Exception();
3090 }
3091 matched = !match->IsNull();
3092 } while (matched);
3093
3094 if (prev < length) {
3095 builder.AddSubjectSlice(prev, length);
3096 }
3097
3098 return *(builder.ToString());
3099}
3100
3101
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003102template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003103MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003104 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003105 String* subject,
3106 JSRegExp* regexp,
3107 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003108 ASSERT(subject->IsFlat());
3109
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003110 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003111
3112 Handle<String> subject_handle(subject);
3113 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003114
3115 // Shortcut for simple non-regexp global replacements
3116 if (regexp_handle->GetFlags().is_global() &&
3117 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3118 Handle<String> empty_string_handle(HEAP->empty_string());
3119 if (subject_handle->HasOnlyAsciiChars()) {
3120 return StringReplaceStringWithString<SeqAsciiString>(
3121 isolate, subject_handle, regexp_handle, empty_string_handle);
3122 } else {
3123 return StringReplaceStringWithString<SeqTwoByteString>(
3124 isolate, subject_handle, regexp_handle, empty_string_handle);
3125 }
3126 }
3127
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003128 Handle<JSArray> last_match_info_handle(last_match_info);
3129 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3130 subject_handle,
3131 0,
3132 last_match_info_handle);
3133 if (match.is_null()) return Failure::Exception();
3134 if (match->IsNull()) return *subject_handle;
3135
3136 ASSERT(last_match_info_handle->HasFastElements());
3137
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003138 int start, end;
3139 {
3140 AssertNoAllocation match_info_array_is_not_in_a_handle;
3141 FixedArray* match_info_array =
3142 FixedArray::cast(last_match_info_handle->elements());
3143
3144 start = RegExpImpl::GetCapture(match_info_array, 0);
3145 end = RegExpImpl::GetCapture(match_info_array, 1);
3146 }
3147
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003148 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003149 int new_length = length - (end - start);
3150 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003151 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003152 }
3153 Handle<ResultSeqString> answer;
3154 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003155 answer = Handle<ResultSeqString>::cast(
3156 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003157 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003158 answer = Handle<ResultSeqString>::cast(
3159 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003160 }
3161
3162 // If the regexp isn't global, only match once.
3163 if (!regexp_handle->GetFlags().is_global()) {
3164 if (start > 0) {
3165 String::WriteToFlat(*subject_handle,
3166 answer->GetChars(),
3167 0,
3168 start);
3169 }
3170 if (end < length) {
3171 String::WriteToFlat(*subject_handle,
3172 answer->GetChars() + start,
3173 end,
3174 length);
3175 }
3176 return *answer;
3177 }
3178
3179 int prev = 0; // Index of end of last match.
3180 int next = 0; // Start of next search (prev unless last match was empty).
3181 int position = 0;
3182
3183 do {
3184 if (prev < start) {
3185 // Add substring subject[prev;start] to answer string.
3186 String::WriteToFlat(*subject_handle,
3187 answer->GetChars() + position,
3188 prev,
3189 start);
3190 position += start - prev;
3191 }
3192 prev = end;
3193 next = end;
3194 // Continue from where the match ended, unless it was an empty match.
3195 if (start == end) {
3196 next++;
3197 if (next > length) break;
3198 }
3199 match = RegExpImpl::Exec(regexp_handle,
3200 subject_handle,
3201 next,
3202 last_match_info_handle);
3203 if (match.is_null()) return Failure::Exception();
3204 if (match->IsNull()) break;
3205
3206 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003207 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003208 {
3209 AssertNoAllocation match_info_array_is_not_in_a_handle;
3210 FixedArray* match_info_array =
3211 FixedArray::cast(last_match_info_handle->elements());
3212 start = RegExpImpl::GetCapture(match_info_array, 0);
3213 end = RegExpImpl::GetCapture(match_info_array, 1);
3214 }
3215 } while (true);
3216
3217 if (prev < length) {
3218 // Add substring subject[prev;length] to answer string.
3219 String::WriteToFlat(*subject_handle,
3220 answer->GetChars() + position,
3221 prev,
3222 length);
3223 position += length - prev;
3224 }
3225
3226 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003227 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003228 }
3229
3230 // Shorten string and fill
3231 int string_size = ResultSeqString::SizeFor(position);
3232 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3233 int delta = allocated_string_size - string_size;
3234
3235 answer->set_length(position);
3236 if (delta == 0) return *answer;
3237
3238 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003239 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003240 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
3241 MemoryChunk::IncrementLiveBytes(answer->address(), -delta);
3242 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003243
3244 return *answer;
3245}
3246
3247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003248RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003249 ASSERT(args.length() == 4);
3250
3251 CONVERT_CHECKED(String, subject, args[0]);
3252 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003253 Object* flat_subject;
3254 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3255 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3256 return maybe_flat_subject;
3257 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003258 }
3259 subject = String::cast(flat_subject);
3260 }
3261
3262 CONVERT_CHECKED(String, replacement, args[2]);
3263 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003264 Object* flat_replacement;
3265 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3266 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3267 return maybe_flat_replacement;
3268 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003269 }
3270 replacement = String::cast(flat_replacement);
3271 }
3272
3273 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3274 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3275
3276 ASSERT(last_match_info->HasFastElements());
3277
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003278 if (replacement->length() == 0) {
3279 if (subject->HasOnlyAsciiChars()) {
3280 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003281 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003282 } else {
3283 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003284 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003285 }
3286 }
3287
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003288 return StringReplaceRegExpWithString(isolate,
3289 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003290 regexp,
3291 replacement,
3292 last_match_info);
3293}
3294
3295
ager@chromium.org7c537e22008-10-16 08:43:32 +00003296// Perform string match of pattern on subject, starting at start index.
3297// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003298// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003299int Runtime::StringMatch(Isolate* isolate,
3300 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003301 Handle<String> pat,
3302 int start_index) {
3303 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003304 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003305
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003306 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003307 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003308
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003309 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003310 if (start_index + pattern_length > subject_length) return -1;
3311
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003312 if (!sub->IsFlat()) FlattenString(sub);
3313 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003314
ager@chromium.org7c537e22008-10-16 08:43:32 +00003315 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003316 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003317 String::FlatContent seq_sub = sub->GetFlatContent();
3318 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003319
ager@chromium.org7c537e22008-10-16 08:43:32 +00003320 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003321 if (seq_pat.IsAscii()) {
3322 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3323 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003324 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003325 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003326 pat_vector,
3327 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003328 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003329 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003330 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003331 pat_vector,
3332 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003333 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003334 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3335 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003336 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003337 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003338 pat_vector,
3339 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003340 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003341 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003342 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003343 pat_vector,
3344 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003345}
3346
3347
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003348RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003349 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003350 ASSERT(args.length() == 3);
3351
ager@chromium.org7c537e22008-10-16 08:43:32 +00003352 CONVERT_ARG_CHECKED(String, sub, 0);
3353 CONVERT_ARG_CHECKED(String, pat, 1);
3354
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003355 Object* index = args[2];
3356 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003357 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003358
ager@chromium.org870a0b62008-11-04 11:43:05 +00003359 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003360 int position =
3361 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003362 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003363}
3364
3365
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003366template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003367static int StringMatchBackwards(Vector<const schar> subject,
3368 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003369 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003370 int pattern_length = pattern.length();
3371 ASSERT(pattern_length >= 1);
3372 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003373
3374 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003375 for (int i = 0; i < pattern_length; i++) {
3376 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003377 if (c > String::kMaxAsciiCharCode) {
3378 return -1;
3379 }
3380 }
3381 }
3382
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003383 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003384 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003385 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003386 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003387 while (j < pattern_length) {
3388 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003389 break;
3390 }
3391 j++;
3392 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003393 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003394 return i;
3395 }
3396 }
3397 return -1;
3398}
3399
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003400RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003401 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003402 ASSERT(args.length() == 3);
3403
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003404 CONVERT_ARG_CHECKED(String, sub, 0);
3405 CONVERT_ARG_CHECKED(String, pat, 1);
3406
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003407 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003408 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003409 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003410
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003411 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003412 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003413
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003414 if (start_index + pat_length > sub_length) {
3415 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003416 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003417
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003418 if (pat_length == 0) {
3419 return Smi::FromInt(start_index);
3420 }
3421
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003422 if (!sub->IsFlat()) FlattenString(sub);
3423 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003424
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003425 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003426 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3427
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003428 String::FlatContent sub_content = sub->GetFlatContent();
3429 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003430
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003431 if (pat_content.IsAscii()) {
3432 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3433 if (sub_content.IsAscii()) {
3434 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003435 pat_vector,
3436 start_index);
3437 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003438 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003439 pat_vector,
3440 start_index);
3441 }
3442 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003443 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3444 if (sub_content.IsAscii()) {
3445 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003446 pat_vector,
3447 start_index);
3448 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003449 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003450 pat_vector,
3451 start_index);
3452 }
3453 }
3454
3455 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003456}
3457
3458
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003459RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003460 NoHandleAllocation ha;
3461 ASSERT(args.length() == 2);
3462
3463 CONVERT_CHECKED(String, str1, args[0]);
3464 CONVERT_CHECKED(String, str2, args[1]);
3465
3466 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003467 int str1_length = str1->length();
3468 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003469
3470 // Decide trivial cases without flattening.
3471 if (str1_length == 0) {
3472 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3473 return Smi::FromInt(-str2_length);
3474 } else {
3475 if (str2_length == 0) return Smi::FromInt(str1_length);
3476 }
3477
3478 int end = str1_length < str2_length ? str1_length : str2_length;
3479
3480 // No need to flatten if we are going to find the answer on the first
3481 // character. At this point we know there is at least one character
3482 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003483 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003484 if (d != 0) return Smi::FromInt(d);
3485
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003486 str1->TryFlatten();
3487 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003488
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003489 StringInputBuffer& buf1 =
3490 *isolate->runtime_state()->string_locale_compare_buf1();
3491 StringInputBuffer& buf2 =
3492 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003493
3494 buf1.Reset(str1);
3495 buf2.Reset(str2);
3496
3497 for (int i = 0; i < end; i++) {
3498 uint16_t char1 = buf1.GetNext();
3499 uint16_t char2 = buf2.GetNext();
3500 if (char1 != char2) return Smi::FromInt(char1 - char2);
3501 }
3502
3503 return Smi::FromInt(str1_length - str2_length);
3504}
3505
3506
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003507RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003508 NoHandleAllocation ha;
3509 ASSERT(args.length() == 3);
3510
3511 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003512 int start, end;
3513 // We have a fast integer-only case here to avoid a conversion to double in
3514 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003515 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3516 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3517 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3518 start = from_number;
3519 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003520 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003521 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3522 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003523 start = FastD2I(from_number);
3524 end = FastD2I(to_number);
3525 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003526 RUNTIME_ASSERT(end >= start);
3527 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003528 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003529 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003530 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003531}
3532
3533
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003534RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003535 ASSERT_EQ(3, args.length());
3536
3537 CONVERT_ARG_CHECKED(String, subject, 0);
3538 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3539 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3540 HandleScope handles;
3541
3542 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3543
3544 if (match.is_null()) {
3545 return Failure::Exception();
3546 }
3547 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003548 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003549 }
3550 int length = subject->length();
3551
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003552 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003553 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003554 int start;
3555 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003556 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003557 {
3558 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003559 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003560 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3561 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3562 }
3563 offsets.Add(start);
3564 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003565 if (start == end) if (++end > length) break;
3566 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003567 if (match.is_null()) {
3568 return Failure::Exception();
3569 }
3570 } while (!match->IsNull());
3571 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003572 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003573 Handle<String> substring = isolate->factory()->
3574 NewSubString(subject, offsets.at(0), offsets.at(1));
3575 elements->set(0, *substring);
3576 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003577 int from = offsets.at(i * 2);
3578 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003579 Handle<String> substring = isolate->factory()->
3580 NewProperSubString(subject, from, to);
3581 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003582 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003583 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003584 result->set_length(Smi::FromInt(matches));
3585 return *result;
3586}
3587
3588
lrn@chromium.org25156de2010-04-06 13:10:27 +00003589// Two smis before and after the match, for very long strings.
3590const int kMaxBuilderEntriesPerRegExpMatch = 5;
3591
3592
3593static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3594 Handle<JSArray> last_match_info,
3595 int match_start,
3596 int match_end) {
3597 // Fill last_match_info with a single capture.
3598 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3599 AssertNoAllocation no_gc;
3600 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3601 RegExpImpl::SetLastCaptureCount(elements, 2);
3602 RegExpImpl::SetLastInput(elements, *subject);
3603 RegExpImpl::SetLastSubject(elements, *subject);
3604 RegExpImpl::SetCapture(elements, 0, match_start);
3605 RegExpImpl::SetCapture(elements, 1, match_end);
3606}
3607
3608
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003609template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003610static bool SearchStringMultiple(Isolate* isolate,
3611 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003612 Vector<const PatternChar> pattern,
3613 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003614 FixedArrayBuilder* builder,
3615 int* match_pos) {
3616 int pos = *match_pos;
3617 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003618 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003619 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003620 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003621 while (pos <= max_search_start) {
3622 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3623 *match_pos = pos;
3624 return false;
3625 }
3626 // Position of end of previous match.
3627 int match_end = pos + pattern_length;
3628 int new_pos = search.Search(subject, match_end);
3629 if (new_pos >= 0) {
3630 // A match.
3631 if (new_pos > match_end) {
3632 ReplacementStringBuilder::AddSubjectSlice(builder,
3633 match_end,
3634 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003635 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003636 pos = new_pos;
3637 builder->Add(pattern_string);
3638 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003639 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003640 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003641 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003642
lrn@chromium.org25156de2010-04-06 13:10:27 +00003643 if (pos < max_search_start) {
3644 ReplacementStringBuilder::AddSubjectSlice(builder,
3645 pos + pattern_length,
3646 subject_length);
3647 }
3648 *match_pos = pos;
3649 return true;
3650}
3651
3652
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003653static bool SearchStringMultiple(Isolate* isolate,
3654 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003655 Handle<String> pattern,
3656 Handle<JSArray> last_match_info,
3657 FixedArrayBuilder* builder) {
3658 ASSERT(subject->IsFlat());
3659 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003660
3661 // Treating as if a previous match was before first character.
3662 int match_pos = -pattern->length();
3663
3664 for (;;) { // Break when search complete.
3665 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3666 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003667 String::FlatContent subject_content = subject->GetFlatContent();
3668 String::FlatContent pattern_content = pattern->GetFlatContent();
3669 if (subject_content.IsAscii()) {
3670 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3671 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003672 if (SearchStringMultiple(isolate,
3673 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003674 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003675 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003676 builder,
3677 &match_pos)) break;
3678 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003679 if (SearchStringMultiple(isolate,
3680 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003681 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003682 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003683 builder,
3684 &match_pos)) break;
3685 }
3686 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003687 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3688 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003689 if (SearchStringMultiple(isolate,
3690 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003691 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003692 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003693 builder,
3694 &match_pos)) break;
3695 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003696 if (SearchStringMultiple(isolate,
3697 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003698 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003699 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003700 builder,
3701 &match_pos)) break;
3702 }
3703 }
3704 }
3705
3706 if (match_pos >= 0) {
3707 SetLastMatchInfoNoCaptures(subject,
3708 last_match_info,
3709 match_pos,
3710 match_pos + pattern->length());
3711 return true;
3712 }
3713 return false; // No matches at all.
3714}
3715
3716
3717static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003718 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003719 Handle<String> subject,
3720 Handle<JSRegExp> regexp,
3721 Handle<JSArray> last_match_array,
3722 FixedArrayBuilder* builder) {
3723 ASSERT(subject->IsFlat());
3724 int match_start = -1;
3725 int match_end = 0;
3726 int pos = 0;
3727 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3728 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3729
3730 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003731 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003732 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003733 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003734
3735 for (;;) { // Break on failure, return on exception.
3736 RegExpImpl::IrregexpResult result =
3737 RegExpImpl::IrregexpExecOnce(regexp,
3738 subject,
3739 pos,
3740 register_vector);
3741 if (result == RegExpImpl::RE_SUCCESS) {
3742 match_start = register_vector[0];
3743 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3744 if (match_end < match_start) {
3745 ReplacementStringBuilder::AddSubjectSlice(builder,
3746 match_end,
3747 match_start);
3748 }
3749 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003750 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003751 if (!first) {
3752 builder->Add(*isolate->factory()->NewProperSubString(subject,
3753 match_start,
3754 match_end));
3755 } else {
3756 builder->Add(*isolate->factory()->NewSubString(subject,
3757 match_start,
3758 match_end));
3759 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003760 if (match_start != match_end) {
3761 pos = match_end;
3762 } else {
3763 pos = match_end + 1;
3764 if (pos > subject_length) break;
3765 }
3766 } else if (result == RegExpImpl::RE_FAILURE) {
3767 break;
3768 } else {
3769 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3770 return result;
3771 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003772 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003773 }
3774
3775 if (match_start >= 0) {
3776 if (match_end < subject_length) {
3777 ReplacementStringBuilder::AddSubjectSlice(builder,
3778 match_end,
3779 subject_length);
3780 }
3781 SetLastMatchInfoNoCaptures(subject,
3782 last_match_array,
3783 match_start,
3784 match_end);
3785 return RegExpImpl::RE_SUCCESS;
3786 } else {
3787 return RegExpImpl::RE_FAILURE; // No matches at all.
3788 }
3789}
3790
3791
3792static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003793 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003794 Handle<String> subject,
3795 Handle<JSRegExp> regexp,
3796 Handle<JSArray> last_match_array,
3797 FixedArrayBuilder* builder) {
3798
3799 ASSERT(subject->IsFlat());
3800 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3801 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3802
3803 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003804 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003805
3806 RegExpImpl::IrregexpResult result =
3807 RegExpImpl::IrregexpExecOnce(regexp,
3808 subject,
3809 0,
3810 register_vector);
3811
3812 int capture_count = regexp->CaptureCount();
3813 int subject_length = subject->length();
3814
3815 // Position to search from.
3816 int pos = 0;
3817 // End of previous match. Differs from pos if match was empty.
3818 int match_end = 0;
3819 if (result == RegExpImpl::RE_SUCCESS) {
3820 // Need to keep a copy of the previous match for creating last_match_info
3821 // at the end, so we have two vectors that we swap between.
3822 OffsetsVector registers2(required_registers);
3823 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003824 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003825 do {
3826 int match_start = register_vector[0];
3827 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3828 if (match_end < match_start) {
3829 ReplacementStringBuilder::AddSubjectSlice(builder,
3830 match_end,
3831 match_start);
3832 }
3833 match_end = register_vector[1];
3834
3835 {
3836 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003837 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003838 // Arguments array to replace function is match, captures, index and
3839 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003840 Handle<FixedArray> elements =
3841 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003842 Handle<String> match;
3843 if (!first) {
3844 match = isolate->factory()->NewProperSubString(subject,
3845 match_start,
3846 match_end);
3847 } else {
3848 match = isolate->factory()->NewSubString(subject,
3849 match_start,
3850 match_end);
3851 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003852 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003853 for (int i = 1; i <= capture_count; i++) {
3854 int start = register_vector[i * 2];
3855 if (start >= 0) {
3856 int end = register_vector[i * 2 + 1];
3857 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003858 Handle<String> substring;
3859 if (!first) {
3860 substring = isolate->factory()->NewProperSubString(subject,
3861 start,
3862 end);
3863 } else {
3864 substring = isolate->factory()->NewSubString(subject, start, end);
3865 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003866 elements->set(i, *substring);
3867 } else {
3868 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003869 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003870 }
3871 }
3872 elements->set(capture_count + 1, Smi::FromInt(match_start));
3873 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003874 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003875 }
3876 // Swap register vectors, so the last successful match is in
3877 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003878 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003879 prev_register_vector = register_vector;
3880 register_vector = tmp;
3881
3882 if (match_end > match_start) {
3883 pos = match_end;
3884 } else {
3885 pos = match_end + 1;
3886 if (pos > subject_length) {
3887 break;
3888 }
3889 }
3890
3891 result = RegExpImpl::IrregexpExecOnce(regexp,
3892 subject,
3893 pos,
3894 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003895 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003896 } while (result == RegExpImpl::RE_SUCCESS);
3897
3898 if (result != RegExpImpl::RE_EXCEPTION) {
3899 // Finished matching, with at least one match.
3900 if (match_end < subject_length) {
3901 ReplacementStringBuilder::AddSubjectSlice(builder,
3902 match_end,
3903 subject_length);
3904 }
3905
3906 int last_match_capture_count = (capture_count + 1) * 2;
3907 int last_match_array_size =
3908 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3909 last_match_array->EnsureSize(last_match_array_size);
3910 AssertNoAllocation no_gc;
3911 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3912 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3913 RegExpImpl::SetLastSubject(elements, *subject);
3914 RegExpImpl::SetLastInput(elements, *subject);
3915 for (int i = 0; i < last_match_capture_count; i++) {
3916 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3917 }
3918 return RegExpImpl::RE_SUCCESS;
3919 }
3920 }
3921 // No matches at all, return failure or exception result directly.
3922 return result;
3923}
3924
3925
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003926RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003927 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003928 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003929
3930 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003931 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003932 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3933 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3934 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3935
3936 ASSERT(last_match_info->HasFastElements());
3937 ASSERT(regexp->GetFlags().is_global());
3938 Handle<FixedArray> result_elements;
3939 if (result_array->HasFastElements()) {
3940 result_elements =
3941 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003942 }
3943 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003944 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003945 }
3946 FixedArrayBuilder builder(result_elements);
3947
3948 if (regexp->TypeTag() == JSRegExp::ATOM) {
3949 Handle<String> pattern(
3950 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003951 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003952 if (SearchStringMultiple(isolate, subject, pattern,
3953 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003954 return *builder.ToJSArray(result_array);
3955 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003956 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003957 }
3958
3959 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3960
3961 RegExpImpl::IrregexpResult result;
3962 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003963 result = SearchRegExpNoCaptureMultiple(isolate,
3964 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003965 regexp,
3966 last_match_info,
3967 &builder);
3968 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003969 result = SearchRegExpMultiple(isolate,
3970 subject,
3971 regexp,
3972 last_match_info,
3973 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003974 }
3975 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003976 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003977 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3978 return Failure::Exception();
3979}
3980
3981
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003982RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003983 NoHandleAllocation ha;
3984 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003985 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003986 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003987
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003988 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003989 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003990 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003991 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003992 // Character array used for conversion.
3993 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003994 return isolate->heap()->
3995 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003996 }
3997 }
3998
3999 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004000 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004001 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004002 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004003 }
4004 if (isinf(value)) {
4005 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004006 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004007 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004008 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004009 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004010 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004011 MaybeObject* result =
4012 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004013 DeleteArray(str);
4014 return result;
4015}
4016
4017
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004018RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004019 NoHandleAllocation ha;
4020 ASSERT(args.length() == 2);
4021
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004022 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004023 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004024 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004025 }
4026 if (isinf(value)) {
4027 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004028 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004029 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004030 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004031 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004032 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004033 int f = FastD2I(f_number);
4034 RUNTIME_ASSERT(f >= 0);
4035 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004036 MaybeObject* res =
4037 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004038 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004039 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004040}
4041
4042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004043RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004044 NoHandleAllocation ha;
4045 ASSERT(args.length() == 2);
4046
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004047 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004048 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004049 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004050 }
4051 if (isinf(value)) {
4052 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004053 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004055 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004056 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004057 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004058 int f = FastD2I(f_number);
4059 RUNTIME_ASSERT(f >= -1 && f <= 20);
4060 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004061 MaybeObject* res =
4062 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004063 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004064 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004065}
4066
4067
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004068RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004069 NoHandleAllocation ha;
4070 ASSERT(args.length() == 2);
4071
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004072 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004073 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004074 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004075 }
4076 if (isinf(value)) {
4077 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004078 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004079 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004080 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004081 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004082 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004083 int f = FastD2I(f_number);
4084 RUNTIME_ASSERT(f >= 1 && f <= 21);
4085 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004086 MaybeObject* res =
4087 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004089 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004090}
4091
4092
4093// Returns a single character string where first character equals
4094// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004095static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004096 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004097 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004098 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004099 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004100 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004101 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004102}
4103
4104
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004105MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4106 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004107 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004108 // Handle [] indexing on Strings
4109 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004110 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4111 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 }
4113
4114 // Handle [] indexing on String objects
4115 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004116 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4117 Handle<Object> result =
4118 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4119 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004120 }
4121
4122 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004123 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004124 return prototype->GetElement(index);
4125 }
4126
4127 return object->GetElement(index);
4128}
4129
4130
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004131MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4132 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004133 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004134 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004135
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004136 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004137 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004138 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004139 isolate->factory()->NewTypeError("non_object_property_load",
4140 HandleVector(args, 2));
4141 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004142 }
4143
4144 // Check if the given key is an array index.
4145 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004146 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004147 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004148 }
4149
4150 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004151 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004152 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004153 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004154 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004155 bool has_pending_exception = false;
4156 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004157 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004158 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004159 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004160 }
4161
ager@chromium.org32912102009-01-16 10:38:43 +00004162 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004163 // the element if so.
4164 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004165 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004166 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004167 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004168 }
4169}
4170
4171
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004172RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004173 NoHandleAllocation ha;
4174 ASSERT(args.length() == 2);
4175
4176 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004177 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004178
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004179 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004180}
4181
4182
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004183MaybeObject* TransitionElements(Handle<Object> object,
4184 ElementsKind to_kind,
4185 Isolate* isolate) {
4186 HandleScope scope(isolate);
4187 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
4188 ElementsKind from_kind =
4189 Handle<JSObject>::cast(object)->map()->elements_kind();
4190 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
4191 Handle<Object> result =
4192 TransitionElementsKind(Handle<JSObject>::cast(object), to_kind);
4193 if (result.is_null()) return isolate->ThrowIllegalOperation();
4194 return *result;
4195 }
4196 return isolate->ThrowIllegalOperation();
4197}
4198
4199
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004200// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004201RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004202 NoHandleAllocation ha;
4203 ASSERT(args.length() == 2);
4204
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004205 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004206 // itself.
4207 //
4208 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004209 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004210 // global proxy object never has properties. This is the case
4211 // because the global proxy object forwards everything to its hidden
4212 // prototype including local lookups.
4213 //
4214 // Additionally, we need to make sure that we do not cache results
4215 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004216 if (args[0]->IsJSObject()) {
4217 if (!args[0]->IsJSGlobalProxy() &&
4218 !args[0]->IsAccessCheckNeeded() &&
4219 args[1]->IsString()) {
4220 JSObject* receiver = JSObject::cast(args[0]);
4221 String* key = String::cast(args[1]);
4222 if (receiver->HasFastProperties()) {
4223 // Attempt to use lookup cache.
4224 Map* receiver_map = receiver->map();
4225 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4226 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4227 if (offset != -1) {
4228 Object* value = receiver->FastPropertyAt(offset);
4229 return value->IsTheHole()
4230 ? isolate->heap()->undefined_value()
4231 : value;
4232 }
4233 // Lookup cache miss. Perform lookup and update the cache if
4234 // appropriate.
4235 LookupResult result(isolate);
4236 receiver->LocalLookup(key, &result);
4237 if (result.IsProperty() && result.type() == FIELD) {
4238 int offset = result.GetFieldIndex();
4239 keyed_lookup_cache->Update(receiver_map, key, offset);
4240 return receiver->FastPropertyAt(offset);
4241 }
4242 } else {
4243 // Attempt dictionary lookup.
4244 StringDictionary* dictionary = receiver->property_dictionary();
4245 int entry = dictionary->FindEntry(key);
4246 if ((entry != StringDictionary::kNotFound) &&
4247 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4248 Object* value = dictionary->ValueAt(entry);
4249 if (!receiver->IsGlobalObject()) return value;
4250 value = JSGlobalPropertyCell::cast(value)->value();
4251 if (!value->IsTheHole()) return value;
4252 // If value is the hole do the general lookup.
4253 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004254 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004255 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4256 // JSObject without a string key. If the key is a Smi, check for a
4257 // definite out-of-bounds access to elements, which is a strong indicator
4258 // that subsequent accesses will also call the runtime. Proactively
4259 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4260 // doubles for those future calls in the case that the elements would
4261 // become FAST_DOUBLE_ELEMENTS.
4262 Handle<JSObject> js_object(args.at<JSObject>(0));
4263 ElementsKind elements_kind = js_object->GetElementsKind();
4264 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4265 elements_kind == FAST_DOUBLE_ELEMENTS) {
4266 FixedArrayBase* elements = js_object->elements();
4267 if (args.at<Smi>(1)->value() >= elements->length()) {
4268 MaybeObject* maybe_object = TransitionElements(js_object,
4269 FAST_ELEMENTS,
4270 isolate);
4271 if (maybe_object->IsFailure()) return maybe_object;
4272 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004273 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004274 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004275 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4276 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004277 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004278 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004279 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004280 if (index >= 0 && index < str->length()) {
4281 Handle<Object> result = GetCharAt(str, index);
4282 return *result;
4283 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004284 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004285
4286 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004287 return Runtime::GetObjectProperty(isolate,
4288 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004289 args.at<Object>(1));
4290}
4291
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004292// Implements part of 8.12.9 DefineOwnProperty.
4293// There are 3 cases that lead here:
4294// Step 4b - define a new accessor property.
4295// Steps 9c & 12 - replace an existing data property with an accessor property.
4296// Step 12 - update an existing accessor property with an accessor or generic
4297// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004298RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004299 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004300 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004301 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4302 CONVERT_CHECKED(String, name, args[1]);
4303 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004304 Object* fun = args[3];
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004305 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004306 CONVERT_CHECKED(Smi, flag_attr, args[4]);
4307 int unchecked = flag_attr->value();
4308 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4309 RUNTIME_ASSERT(!obj->IsNull());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004310 LookupResult result(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004311 obj->LocalLookupRealNamedProperty(name, &result);
4312
4313 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4314 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
4315 // delete it to avoid running into trouble in DefineAccessor, which
4316 // handles this incorrectly if the property is readonly (does nothing)
4317 if (result.IsProperty() &&
4318 (result.type() == FIELD || result.type() == NORMAL
4319 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004320 Object* ok;
4321 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004322 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004323 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4324 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004325 }
4326 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4327}
4328
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004329// Implements part of 8.12.9 DefineOwnProperty.
4330// There are 3 cases that lead here:
4331// Step 4a - define a new data property.
4332// Steps 9b & 12 - replace an existing accessor property with a data property.
4333// Step 12 - update an existing data property with a data or generic
4334// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004335RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004336 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004337 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004338 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4339 CONVERT_ARG_CHECKED(String, name, 1);
4340 Handle<Object> obj_value = args.at<Object>(2);
4341
4342 CONVERT_CHECKED(Smi, flag, args[3]);
4343 int unchecked = flag->value();
4344 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4345
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004346 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4347
4348 // Check if this is an element.
4349 uint32_t index;
4350 bool is_element = name->AsArrayIndex(&index);
4351
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004352 // Special case for elements if any of the flags might be involved.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004353 // If elements are in fast case we always implicitly assume that:
4354 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004355 if (is_element && (attr != NONE ||
4356 js_object->HasLocalElement(index) == JSObject::DICTIONARY_ELEMENT)) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004357 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004358 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004359 // We do not need to do access checks here since these has already
4360 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004361 Handle<Object> proto(js_object->GetPrototype());
4362 // If proxy is detached, ignore the assignment. Alternatively,
4363 // we could throw an exception.
4364 if (proto->IsNull()) return *obj_value;
4365 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004366 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004367
4368 // Don't allow element properties to be redefined on objects with external
4369 // array elements.
4370 if (js_object->HasExternalArrayElements()) {
4371 Handle<Object> args[2] = { js_object, name };
4372 Handle<Object> error =
4373 isolate->factory()->NewTypeError("redef_external_array_element",
4374 HandleVector(args, 2));
4375 return isolate->Throw(*error);
4376 }
4377
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004378 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004379 // Make sure that we never go back to fast case.
4380 dictionary->set_requires_slow_elements();
4381 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004382 Handle<NumberDictionary> extended_dictionary =
4383 NumberDictionarySet(dictionary, index, obj_value, details);
4384 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004385 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004386 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4387 } else {
4388 js_object->set_elements(*extended_dictionary);
4389 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004390 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004391 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004392 }
4393
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004394 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004395 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004396
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004397 // To be compatible with safari we do not change the value on API objects
4398 // in defineProperty. Firefox disagrees here, and actually changes the value.
4399 if (result.IsProperty() &&
4400 (result.type() == CALLBACKS) &&
4401 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004402 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004403 }
4404
ager@chromium.org5c838252010-02-19 08:53:10 +00004405 // Take special care when attributes are different and there is already
4406 // a property. For simplicity we normalize the property which enables us
4407 // to not worry about changing the instance_descriptor and creating a new
4408 // map. The current version of SetObjectProperty does not handle attributes
4409 // correctly in the case where a property is a field and is reset with
4410 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004411 if (result.IsProperty() &&
4412 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004413 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004414 if (js_object->IsJSGlobalProxy()) {
4415 // Since the result is a property, the prototype will exist so
4416 // we don't have to check for null.
4417 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004418 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004419 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004420 // Use IgnoreAttributes version since a readonly property may be
4421 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004422 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4423 *obj_value,
4424 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004425 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004426
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004427 return Runtime::ForceSetObjectProperty(isolate,
4428 js_object,
4429 name,
4430 obj_value,
4431 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004432}
4433
4434
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004435// Special case for elements if any of the flags are true.
4436// If elements are in fast case we always implicitly assume that:
4437// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4438static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4439 Handle<JSObject> js_object,
4440 uint32_t index,
4441 Handle<Object> value,
4442 PropertyAttributes attr) {
4443 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004444 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004445 // Make sure that we never go back to fast case.
4446 dictionary->set_requires_slow_elements();
4447 PropertyDetails details = PropertyDetails(attr, NORMAL);
4448 Handle<NumberDictionary> extended_dictionary =
4449 NumberDictionarySet(dictionary, index, value, details);
4450 if (*extended_dictionary != *dictionary) {
4451 js_object->set_elements(*extended_dictionary);
4452 }
4453 return *value;
4454}
4455
4456
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004457MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4458 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004459 Handle<Object> key,
4460 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004461 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004462 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004463 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004464
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004465 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004466 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004467 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004468 isolate->factory()->NewTypeError("non_object_property_store",
4469 HandleVector(args, 2));
4470 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004471 }
4472
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004473 if (object->IsJSProxy()) {
4474 bool has_pending_exception = false;
4475 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4476 if (has_pending_exception) return Failure::Exception();
4477 return JSProxy::cast(*object)->SetProperty(
4478 String::cast(*name), *value, attr, strict_mode);
4479 }
4480
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004481 // If the object isn't a JavaScript object, we ignore the store.
4482 if (!object->IsJSObject()) return *value;
4483
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004484 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4485
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004486 // Check if the given key is an array index.
4487 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004488 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004489 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4490 // of a string using [] notation. We need to support this too in
4491 // JavaScript.
4492 // In the case of a String object we just need to redirect the assignment to
4493 // the underlying string if the index is in range. Since the underlying
4494 // string does nothing with the assignment then we can ignore such
4495 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004496 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004497 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004498 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004499
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004500 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4501 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4502 }
4503
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004504 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004505 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004506 return *value;
4507 }
4508
4509 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004510 Handle<Object> result;
4511 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004512 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4513 return NormalizeObjectSetElement(isolate,
4514 js_object,
4515 index,
4516 value,
4517 attr);
4518 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004519 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004520 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004521 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004522 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004523 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004524 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004525 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004526 return *value;
4527 }
4528
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004529 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004530 bool has_pending_exception = false;
4531 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4532 if (has_pending_exception) return Failure::Exception();
4533 Handle<String> name = Handle<String>::cast(converted);
4534
4535 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004536 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004537 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004538 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004539 }
4540}
4541
4542
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004543MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4544 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004545 Handle<Object> key,
4546 Handle<Object> value,
4547 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004548 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004549
4550 // Check if the given key is an array index.
4551 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004552 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004553 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4554 // of a string using [] notation. We need to support this too in
4555 // JavaScript.
4556 // In the case of a String object we just need to redirect the assignment to
4557 // the underlying string if the index is in range. Since the underlying
4558 // string does nothing with the assignment then we can ignore such
4559 // assignments.
4560 if (js_object->IsStringObjectWithCharacterAt(index)) {
4561 return *value;
4562 }
4563
whesse@chromium.org7b260152011-06-20 15:33:18 +00004564 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004565 }
4566
4567 if (key->IsString()) {
4568 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004569 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004570 } else {
4571 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004572 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004573 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4574 *value,
4575 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004576 }
4577 }
4578
4579 // Call-back into JavaScript to convert the key to a string.
4580 bool has_pending_exception = false;
4581 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4582 if (has_pending_exception) return Failure::Exception();
4583 Handle<String> name = Handle<String>::cast(converted);
4584
4585 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004586 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004587 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004588 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004589 }
4590}
4591
4592
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004593MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004594 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004595 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004596 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004597
4598 // Check if the given key is an array index.
4599 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004600 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004601 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4602 // characters of a string using [] notation. In the case of a
4603 // String object we just need to redirect the deletion to the
4604 // underlying string if the index is in range. Since the
4605 // underlying string does nothing with the deletion, we can ignore
4606 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004607 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004608 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004609 }
4610
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004611 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004612 }
4613
4614 Handle<String> key_string;
4615 if (key->IsString()) {
4616 key_string = Handle<String>::cast(key);
4617 } else {
4618 // Call-back into JavaScript to convert the key to a string.
4619 bool has_pending_exception = false;
4620 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4621 if (has_pending_exception) return Failure::Exception();
4622 key_string = Handle<String>::cast(converted);
4623 }
4624
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004625 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004626 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004627}
4628
4629
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004630RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004631 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004632 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004633
4634 Handle<Object> object = args.at<Object>(0);
4635 Handle<Object> key = args.at<Object>(1);
4636 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004637 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004638 RUNTIME_ASSERT(
4639 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004640 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004641 PropertyAttributes attributes =
4642 static_cast<PropertyAttributes>(unchecked_attributes);
4643
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004644 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004645 if (args.length() == 5) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004646 CONVERT_STRICT_MODE_ARG(strict_mode_flag, 4);
4647 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004648 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004649
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004650 return Runtime::SetObjectProperty(isolate,
4651 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004652 key,
4653 value,
4654 attributes,
4655 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004656}
4657
4658
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004659RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4660 NoHandleAllocation ha;
4661 RUNTIME_ASSERT(args.length() == 1);
4662 Handle<Object> object = args.at<Object>(0);
4663 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4664}
4665
4666
4667RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4668 NoHandleAllocation ha;
4669 RUNTIME_ASSERT(args.length() == 1);
4670 Handle<Object> object = args.at<Object>(0);
4671 return TransitionElements(object, FAST_ELEMENTS, isolate);
4672}
4673
4674
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004675// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004676// This is used to decide if we should transform null and undefined
4677// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004678RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004679 NoHandleAllocation ha;
4680 RUNTIME_ASSERT(args.length() == 1);
4681
4682 Handle<Object> object = args.at<Object>(0);
4683
4684 if (object->IsJSFunction()) {
4685 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004686 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004687 }
4688 return isolate->heap()->undefined_value();
4689}
4690
4691
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004692RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4693 RUNTIME_ASSERT(args.length() == 5);
4694 CONVERT_ARG_CHECKED(JSObject, object, 0);
4695 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4696 Handle<Object> value = args.at<Object>(2);
4697 CONVERT_ARG_CHECKED(FixedArray, literals, 3);
4698 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4699 HandleScope scope;
4700
4701 Object* raw_boilerplate_object = literals->get(literal_index);
4702 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4703#if DEBUG
4704 ElementsKind elements_kind = object->GetElementsKind();
4705#endif
4706 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4707 // Smis should never trigger transitions.
4708 ASSERT(!value->IsSmi());
4709
4710 if (value->IsNumber()) {
4711 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
4712 TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4713 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4714 FixedDoubleArray* double_array =
4715 FixedDoubleArray::cast(object->elements());
4716 HeapNumber* number = HeapNumber::cast(*value);
4717 double_array->set(store_index, number->Number());
4718 } else {
4719 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4720 elements_kind == FAST_DOUBLE_ELEMENTS);
4721 TransitionElementsKind(object, FAST_ELEMENTS);
4722 FixedArray* object_array =
4723 FixedArray::cast(object->elements());
4724 object_array->set(store_index, *value);
4725 }
4726 return *object;
4727}
4728
4729
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004730// Set a local property, even if it is READ_ONLY. If the property does not
4731// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004732RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004733 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004734 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004735 CONVERT_CHECKED(JSObject, object, args[0]);
4736 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004737 // Compute attributes.
4738 PropertyAttributes attributes = NONE;
4739 if (args.length() == 4) {
4740 CONVERT_CHECKED(Smi, value_obj, args[3]);
4741 int unchecked_value = value_obj->value();
4742 // Only attribute bits should be set.
4743 RUNTIME_ASSERT(
4744 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4745 attributes = static_cast<PropertyAttributes>(unchecked_value);
4746 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004747
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004748 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004749 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004750}
4751
4752
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004753RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004754 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004755 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004756
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004757 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004758 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004759 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004760 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004761 ? JSReceiver::STRICT_DELETION
4762 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004763}
4764
4765
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004766static Object* HasLocalPropertyImplementation(Isolate* isolate,
4767 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004768 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004769 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004770 // Handle hidden prototypes. If there's a hidden prototype above this thing
4771 // then we have to check it for properties, because they are supposed to
4772 // look like they are on this object.
4773 Handle<Object> proto(object->GetPrototype());
4774 if (proto->IsJSObject() &&
4775 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004776 return HasLocalPropertyImplementation(isolate,
4777 Handle<JSObject>::cast(proto),
4778 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004779 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004780 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004781}
4782
4783
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004784RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004785 NoHandleAllocation ha;
4786 ASSERT(args.length() == 2);
4787 CONVERT_CHECKED(String, key, args[1]);
4788
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004789 uint32_t index;
4790 const bool key_is_array_index = key->AsArrayIndex(&index);
4791
ager@chromium.org9085a012009-05-11 19:22:57 +00004792 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004793 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004794 if (obj->IsJSObject()) {
4795 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004796 // Fast case: either the key is a real named property or it is not
4797 // an array index and there are no interceptors or hidden
4798 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004799 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004800 Map* map = object->map();
4801 if (!key_is_array_index &&
4802 !map->has_named_interceptor() &&
4803 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4804 return isolate->heap()->false_value();
4805 }
4806 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004807 HandleScope scope(isolate);
4808 return HasLocalPropertyImplementation(isolate,
4809 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004810 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004811 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004812 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004813 String* string = String::cast(obj);
4814 if (index < static_cast<uint32_t>(string->length())) {
4815 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004816 }
4817 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004818 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004819}
4820
4821
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004822RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004823 NoHandleAllocation na;
4824 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004825 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4826 CONVERT_CHECKED(String, key, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004827
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004828 bool result = receiver->HasProperty(key);
4829 if (isolate->has_pending_exception()) return Failure::Exception();
4830 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831}
4832
4833
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004834RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004835 NoHandleAllocation na;
4836 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004837 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4838 CONVERT_CHECKED(Smi, index, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004839
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004840 bool result = receiver->HasElement(index->value());
4841 if (isolate->has_pending_exception()) return Failure::Exception();
4842 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004843}
4844
4845
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004846RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004847 NoHandleAllocation ha;
4848 ASSERT(args.length() == 2);
4849
4850 CONVERT_CHECKED(JSObject, object, args[0]);
4851 CONVERT_CHECKED(String, key, args[1]);
4852
4853 uint32_t index;
4854 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004855 JSObject::LocalElementType type = object->HasLocalElement(index);
4856 switch (type) {
4857 case JSObject::UNDEFINED_ELEMENT:
4858 case JSObject::STRING_CHARACTER_ELEMENT:
4859 return isolate->heap()->false_value();
4860 case JSObject::INTERCEPTED_ELEMENT:
4861 case JSObject::FAST_ELEMENT:
4862 return isolate->heap()->true_value();
4863 case JSObject::DICTIONARY_ELEMENT: {
4864 if (object->IsJSGlobalProxy()) {
4865 Object* proto = object->GetPrototype();
4866 if (proto->IsNull()) {
4867 return isolate->heap()->false_value();
4868 }
4869 ASSERT(proto->IsJSGlobalObject());
4870 object = JSObject::cast(proto);
4871 }
4872 FixedArray* elements = FixedArray::cast(object->elements());
4873 NumberDictionary* dictionary = NULL;
4874 if (elements->map() ==
4875 isolate->heap()->non_strict_arguments_elements_map()) {
4876 dictionary = NumberDictionary::cast(elements->get(1));
4877 } else {
4878 dictionary = NumberDictionary::cast(elements);
4879 }
4880 int entry = dictionary->FindEntry(index);
4881 ASSERT(entry != NumberDictionary::kNotFound);
4882 PropertyDetails details = dictionary->DetailsAt(entry);
4883 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4884 }
4885 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004886 }
4887
ager@chromium.org870a0b62008-11-04 11:43:05 +00004888 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004889 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004890}
4891
4892
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004893RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004894 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004895 ASSERT(args.length() == 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004896 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4897 bool threw = false;
4898 Handle<JSArray> result = GetKeysFor(object, &threw);
4899 if (threw) return Failure::Exception();
4900 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004901}
4902
4903
4904// Returns either a FixedArray as Runtime_GetPropertyNames,
4905// or, if the given object has an enum cache that contains
4906// all enumerable properties of the object and its prototypes
4907// have none, the map of the object. This is used to speed up
4908// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004909RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004910 ASSERT(args.length() == 1);
4911
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004912 CONVERT_CHECKED(JSReceiver, raw_object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004913
4914 if (raw_object->IsSimpleEnum()) return raw_object->map();
4915
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004916 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004917 Handle<JSReceiver> object(raw_object);
4918 bool threw = false;
4919 Handle<FixedArray> content =
4920 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4921 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004922
4923 // Test again, since cache may have been built by preceding call.
4924 if (object->IsSimpleEnum()) return object->map();
4925
4926 return *content;
4927}
4928
4929
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004930// Find the length of the prototype chain that is to to handled as one. If a
4931// prototype object is hidden it is to be viewed as part of the the object it
4932// is prototype for.
4933static int LocalPrototypeChainLength(JSObject* obj) {
4934 int count = 1;
4935 Object* proto = obj->GetPrototype();
4936 while (proto->IsJSObject() &&
4937 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4938 count++;
4939 proto = JSObject::cast(proto)->GetPrototype();
4940 }
4941 return count;
4942}
4943
4944
4945// Return the names of the local named properties.
4946// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004947RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004948 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004949 ASSERT(args.length() == 1);
4950 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004951 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004952 }
4953 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4954
4955 // Skip the global proxy as it has no properties and always delegates to the
4956 // real global object.
4957 if (obj->IsJSGlobalProxy()) {
4958 // Only collect names if access is permitted.
4959 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004960 !isolate->MayNamedAccess(*obj,
4961 isolate->heap()->undefined_value(),
4962 v8::ACCESS_KEYS)) {
4963 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4964 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004965 }
4966 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4967 }
4968
4969 // Find the number of objects making up this.
4970 int length = LocalPrototypeChainLength(*obj);
4971
4972 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004973 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004974 int total_property_count = 0;
4975 Handle<JSObject> jsproto = obj;
4976 for (int i = 0; i < length; i++) {
4977 // Only collect names if access is permitted.
4978 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004979 !isolate->MayNamedAccess(*jsproto,
4980 isolate->heap()->undefined_value(),
4981 v8::ACCESS_KEYS)) {
4982 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4983 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004984 }
4985 int n;
4986 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4987 local_property_count[i] = n;
4988 total_property_count += n;
4989 if (i < length - 1) {
4990 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4991 }
4992 }
4993
4994 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004995 Handle<FixedArray> names =
4996 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004997
4998 // Get the property names.
4999 jsproto = obj;
5000 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005001 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005002 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005003 jsproto->GetLocalPropertyNames(*names, next_copy_index);
5004 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00005005 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005006 proto_with_hidden_properties++;
5007 }
5008 if (i < length - 1) {
5009 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5010 }
5011 }
5012
5013 // Filter out name of hidden propeties object.
5014 if (proto_with_hidden_properties > 0) {
5015 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005016 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005017 names->length() - proto_with_hidden_properties);
5018 int dest_pos = 0;
5019 for (int i = 0; i < total_property_count; i++) {
5020 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005021 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005022 continue;
5023 }
5024 names->set(dest_pos++, name);
5025 }
5026 }
5027
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005028 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005029}
5030
5031
5032// Return the names of the local indexed properties.
5033// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005034RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005035 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005036 ASSERT(args.length() == 1);
5037 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005038 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005039 }
5040 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5041
5042 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005043 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005044 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005045 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005046}
5047
5048
5049// Return information on whether an object has a named or indexed interceptor.
5050// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005051RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005052 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005053 ASSERT(args.length() == 1);
5054 if (!args[0]->IsJSObject()) {
5055 return Smi::FromInt(0);
5056 }
5057 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5058
5059 int result = 0;
5060 if (obj->HasNamedInterceptor()) result |= 2;
5061 if (obj->HasIndexedInterceptor()) result |= 1;
5062
5063 return Smi::FromInt(result);
5064}
5065
5066
5067// Return property names from named interceptor.
5068// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005069RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005070 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005071 ASSERT(args.length() == 1);
5072 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5073
5074 if (obj->HasNamedInterceptor()) {
5075 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5076 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5077 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005078 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005079}
5080
5081
5082// Return element names from indexed interceptor.
5083// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005084RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005085 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005086 ASSERT(args.length() == 1);
5087 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5088
5089 if (obj->HasIndexedInterceptor()) {
5090 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5091 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5092 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005093 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005094}
5095
5096
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005097RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005098 ASSERT_EQ(args.length(), 1);
5099 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005100 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005101 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005102
5103 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005104 // Do access checks before going to the global object.
5105 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005106 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005107 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005108 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5109 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005110 }
5111
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005112 Handle<Object> proto(object->GetPrototype());
5113 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005114 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005115 object = Handle<JSObject>::cast(proto);
5116 }
5117
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005118 bool threw = false;
5119 Handle<FixedArray> contents =
5120 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5121 if (threw) return Failure::Exception();
5122
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005123 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5124 // property array and since the result is mutable we have to create
5125 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005126 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005127 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005128 for (int i = 0; i < length; i++) {
5129 Object* entry = contents->get(i);
5130 if (entry->IsString()) {
5131 copy->set(i, entry);
5132 } else {
5133 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005134 HandleScope scope(isolate);
5135 Handle<Object> entry_handle(entry, isolate);
5136 Handle<Object> entry_str =
5137 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005138 copy->set(i, *entry_str);
5139 }
5140 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005141 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005142}
5143
5144
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005145RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005146 NoHandleAllocation ha;
5147 ASSERT(args.length() == 1);
5148
5149 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005150 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005151 it.AdvanceToArgumentsFrame();
5152 JavaScriptFrame* frame = it.frame();
5153
5154 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005155 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005156
5157 // Try to convert the key to an index. If successful and within
5158 // index return the the argument from the frame.
5159 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005160 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005161 return frame->GetParameter(index);
5162 }
5163
5164 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005165 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005166 bool exception = false;
5167 Handle<Object> converted =
5168 Execution::ToString(args.at<Object>(0), &exception);
5169 if (exception) return Failure::Exception();
5170 Handle<String> key = Handle<String>::cast(converted);
5171
5172 // Try to convert the string key into an array index.
5173 if (key->AsArrayIndex(&index)) {
5174 if (index < n) {
5175 return frame->GetParameter(index);
5176 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005177 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005178 }
5179 }
5180
5181 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005182 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5183 if (key->Equals(isolate->heap()->callee_symbol())) {
5184 Object* function = frame->function();
5185 if (function->IsJSFunction() &&
5186 JSFunction::cast(function)->shared()->strict_mode()) {
5187 return isolate->Throw(*isolate->factory()->NewTypeError(
5188 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5189 }
5190 return function;
5191 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005192
5193 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005194 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005195}
5196
5197
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005198RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005199 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005200
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005201 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005202 Handle<Object> object = args.at<Object>(0);
5203 if (object->IsJSObject()) {
5204 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00005205 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005206 MaybeObject* ok = js_object->TransformToFastProperties(0);
5207 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00005208 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005209 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005210 return *object;
5211}
5212
5213
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005214RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005215 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005216
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005217 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005218 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005219 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005220 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005221 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005222 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005223 return *object;
5224}
5225
5226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005227RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005228 NoHandleAllocation ha;
5229 ASSERT(args.length() == 1);
5230
5231 return args[0]->ToBoolean();
5232}
5233
5234
5235// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5236// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005237RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005238 NoHandleAllocation ha;
5239
5240 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005241 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005242 HeapObject* heap_obj = HeapObject::cast(obj);
5243
5244 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005245 if (heap_obj->map()->is_undetectable()) {
5246 return isolate->heap()->undefined_symbol();
5247 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005248
5249 InstanceType instance_type = heap_obj->map()->instance_type();
5250 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005251 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005252 }
5253
5254 switch (instance_type) {
5255 case ODDBALL_TYPE:
5256 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005257 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005258 }
5259 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005260 return FLAG_harmony_typeof
5261 ? isolate->heap()->null_symbol()
5262 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005263 }
5264 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005265 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005266 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005267 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005268 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005269 default:
5270 // For any kind of object not handled above, the spec rule for
5271 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005272 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005273 }
5274}
5275
5276
lrn@chromium.org25156de2010-04-06 13:10:27 +00005277static bool AreDigits(const char*s, int from, int to) {
5278 for (int i = from; i < to; i++) {
5279 if (s[i] < '0' || s[i] > '9') return false;
5280 }
5281
5282 return true;
5283}
5284
5285
5286static int ParseDecimalInteger(const char*s, int from, int to) {
5287 ASSERT(to - from < 10); // Overflow is not possible.
5288 ASSERT(from < to);
5289 int d = s[from] - '0';
5290
5291 for (int i = from + 1; i < to; i++) {
5292 d = 10 * d + (s[i] - '0');
5293 }
5294
5295 return d;
5296}
5297
5298
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005299RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005300 NoHandleAllocation ha;
5301 ASSERT(args.length() == 1);
5302 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005303 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005304
5305 // Fast case: short integer or some sorts of junk values.
5306 int len = subject->length();
5307 if (subject->IsSeqAsciiString()) {
5308 if (len == 0) return Smi::FromInt(0);
5309
5310 char const* data = SeqAsciiString::cast(subject)->GetChars();
5311 bool minus = (data[0] == '-');
5312 int start_pos = (minus ? 1 : 0);
5313
5314 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005315 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005316 } else if (data[start_pos] > '9') {
5317 // Fast check for a junk value. A valid string may start from a
5318 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5319 // the 'I' character ('Infinity'). All of that have codes not greater than
5320 // '9' except 'I'.
5321 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005322 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005323 }
5324 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5325 // The maximal/minimal smi has 10 digits. If the string has less digits we
5326 // know it will fit into the smi-data type.
5327 int d = ParseDecimalInteger(data, start_pos, len);
5328 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005329 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005330 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005331 } else if (!subject->HasHashCode() &&
5332 len <= String::kMaxArrayIndexSize &&
5333 (len == 1 || data[0] != '0')) {
5334 // String hash is not calculated yet but all the data are present.
5335 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005336 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005337#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005338 subject->Hash(); // Force hash calculation.
5339 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5340 static_cast<int>(hash));
5341#endif
5342 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005343 }
5344 return Smi::FromInt(d);
5345 }
5346 }
5347
5348 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005349 return isolate->heap()->NumberFromDouble(
5350 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005351}
5352
5353
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005354RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005355 NoHandleAllocation ha;
5356 ASSERT(args.length() == 1);
5357
5358 CONVERT_CHECKED(JSArray, codes, args[0]);
5359 int length = Smi::cast(codes->length())->value();
5360
5361 // Check if the string can be ASCII.
5362 int i;
5363 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005364 Object* element;
5365 { MaybeObject* maybe_element = codes->GetElement(i);
5366 // We probably can't get an exception here, but just in order to enforce
5367 // the checking of inputs in the runtime calls we check here.
5368 if (!maybe_element->ToObject(&element)) return maybe_element;
5369 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005370 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5371 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5372 break;
5373 }
5374
lrn@chromium.org303ada72010-10-27 09:33:13 +00005375 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005376 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005377 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005378 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005379 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005380 }
5381
lrn@chromium.org303ada72010-10-27 09:33:13 +00005382 Object* object = NULL;
5383 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005384 String* result = String::cast(object);
5385 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005386 Object* element;
5387 { MaybeObject* maybe_element = codes->GetElement(i);
5388 if (!maybe_element->ToObject(&element)) return maybe_element;
5389 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005390 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005391 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005392 }
5393 return result;
5394}
5395
5396
5397// kNotEscaped is generated by the following:
5398//
5399// #!/bin/perl
5400// for (my $i = 0; $i < 256; $i++) {
5401// print "\n" if $i % 16 == 0;
5402// my $c = chr($i);
5403// my $escaped = 1;
5404// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5405// print $escaped ? "0, " : "1, ";
5406// }
5407
5408
5409static bool IsNotEscaped(uint16_t character) {
5410 // Only for 8 bit characters, the rest are always escaped (in a different way)
5411 ASSERT(character < 256);
5412 static const char kNotEscaped[256] = {
5413 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5414 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5415 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5416 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5417 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5418 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5419 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5420 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5421 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5422 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5423 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5424 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5425 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5426 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5427 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5428 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5429 };
5430 return kNotEscaped[character] != 0;
5431}
5432
5433
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005434RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005435 const char hex_chars[] = "0123456789ABCDEF";
5436 NoHandleAllocation ha;
5437 ASSERT(args.length() == 1);
5438 CONVERT_CHECKED(String, source, args[0]);
5439
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005440 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005441
5442 int escaped_length = 0;
5443 int length = source->length();
5444 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005445 Access<StringInputBuffer> buffer(
5446 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005447 buffer->Reset(source);
5448 while (buffer->has_more()) {
5449 uint16_t character = buffer->GetNext();
5450 if (character >= 256) {
5451 escaped_length += 6;
5452 } else if (IsNotEscaped(character)) {
5453 escaped_length++;
5454 } else {
5455 escaped_length += 3;
5456 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005457 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005458 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005459 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005460 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005461 return Failure::OutOfMemoryException();
5462 }
5463 }
5464 }
5465 // No length change implies no change. Return original string if no change.
5466 if (escaped_length == length) {
5467 return source;
5468 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005469 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005470 { MaybeObject* maybe_o =
5471 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005472 if (!maybe_o->ToObject(&o)) return maybe_o;
5473 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005474 String* destination = String::cast(o);
5475 int dest_position = 0;
5476
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005477 Access<StringInputBuffer> buffer(
5478 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005479 buffer->Rewind();
5480 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005481 uint16_t chr = buffer->GetNext();
5482 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005483 destination->Set(dest_position, '%');
5484 destination->Set(dest_position+1, 'u');
5485 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5486 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5487 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5488 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005489 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005490 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005491 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005492 dest_position++;
5493 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005494 destination->Set(dest_position, '%');
5495 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5496 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005497 dest_position += 3;
5498 }
5499 }
5500 return destination;
5501}
5502
5503
5504static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5505 static const signed char kHexValue['g'] = {
5506 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5507 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5508 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5509 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5510 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5511 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5512 -1, 10, 11, 12, 13, 14, 15 };
5513
5514 if (character1 > 'f') return -1;
5515 int hi = kHexValue[character1];
5516 if (hi == -1) return -1;
5517 if (character2 > 'f') return -1;
5518 int lo = kHexValue[character2];
5519 if (lo == -1) return -1;
5520 return (hi << 4) + lo;
5521}
5522
5523
ager@chromium.org870a0b62008-11-04 11:43:05 +00005524static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005525 int i,
5526 int length,
5527 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005528 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005529 int32_t hi = 0;
5530 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005531 if (character == '%' &&
5532 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005533 source->Get(i + 1) == 'u' &&
5534 (hi = TwoDigitHex(source->Get(i + 2),
5535 source->Get(i + 3))) != -1 &&
5536 (lo = TwoDigitHex(source->Get(i + 4),
5537 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005538 *step = 6;
5539 return (hi << 8) + lo;
5540 } else if (character == '%' &&
5541 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005542 (lo = TwoDigitHex(source->Get(i + 1),
5543 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005544 *step = 3;
5545 return lo;
5546 } else {
5547 *step = 1;
5548 return character;
5549 }
5550}
5551
5552
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005553RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005554 NoHandleAllocation ha;
5555 ASSERT(args.length() == 1);
5556 CONVERT_CHECKED(String, source, args[0]);
5557
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005558 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005559
5560 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005561 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005562
5563 int unescaped_length = 0;
5564 for (int i = 0; i < length; unescaped_length++) {
5565 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005566 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005567 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005568 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005569 i += step;
5570 }
5571
5572 // No length change implies no change. Return original string if no change.
5573 if (unescaped_length == length)
5574 return source;
5575
lrn@chromium.org303ada72010-10-27 09:33:13 +00005576 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005577 { MaybeObject* maybe_o =
5578 ascii ?
5579 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5580 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005581 if (!maybe_o->ToObject(&o)) return maybe_o;
5582 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005583 String* destination = String::cast(o);
5584
5585 int dest_position = 0;
5586 for (int i = 0; i < length; dest_position++) {
5587 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005588 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005589 i += step;
5590 }
5591 return destination;
5592}
5593
5594
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005595static const unsigned int kQuoteTableLength = 128u;
5596
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005597static const int kJsonQuotesCharactersPerEntry = 8;
5598static const char* const JsonQuotes =
5599 "\\u0000 \\u0001 \\u0002 \\u0003 "
5600 "\\u0004 \\u0005 \\u0006 \\u0007 "
5601 "\\b \\t \\n \\u000b "
5602 "\\f \\r \\u000e \\u000f "
5603 "\\u0010 \\u0011 \\u0012 \\u0013 "
5604 "\\u0014 \\u0015 \\u0016 \\u0017 "
5605 "\\u0018 \\u0019 \\u001a \\u001b "
5606 "\\u001c \\u001d \\u001e \\u001f "
5607 " ! \\\" # "
5608 "$ % & ' "
5609 "( ) * + "
5610 ", - . / "
5611 "0 1 2 3 "
5612 "4 5 6 7 "
5613 "8 9 : ; "
5614 "< = > ? "
5615 "@ A B C "
5616 "D E F G "
5617 "H I J K "
5618 "L M N O "
5619 "P Q R S "
5620 "T U V W "
5621 "X Y Z [ "
5622 "\\\\ ] ^ _ "
5623 "` a b c "
5624 "d e f g "
5625 "h i j k "
5626 "l m n o "
5627 "p q r s "
5628 "t u v w "
5629 "x y z { "
5630 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005631
5632
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005633// For a string that is less than 32k characters it should always be
5634// possible to allocate it in new space.
5635static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5636
5637
5638// Doing JSON quoting cannot make the string more than this many times larger.
5639static const int kJsonQuoteWorstCaseBlowup = 6;
5640
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005641static const int kSpaceForQuotesAndComma = 3;
5642static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005643
5644// Covers the entire ASCII range (all other characters are unchanged by JSON
5645// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005646static const byte JsonQuoteLengths[kQuoteTableLength] = {
5647 6, 6, 6, 6, 6, 6, 6, 6,
5648 2, 2, 2, 6, 2, 2, 6, 6,
5649 6, 6, 6, 6, 6, 6, 6, 6,
5650 6, 6, 6, 6, 6, 6, 6, 6,
5651 1, 1, 2, 1, 1, 1, 1, 1,
5652 1, 1, 1, 1, 1, 1, 1, 1,
5653 1, 1, 1, 1, 1, 1, 1, 1,
5654 1, 1, 1, 1, 1, 1, 1, 1,
5655 1, 1, 1, 1, 1, 1, 1, 1,
5656 1, 1, 1, 1, 1, 1, 1, 1,
5657 1, 1, 1, 1, 1, 1, 1, 1,
5658 1, 1, 1, 1, 2, 1, 1, 1,
5659 1, 1, 1, 1, 1, 1, 1, 1,
5660 1, 1, 1, 1, 1, 1, 1, 1,
5661 1, 1, 1, 1, 1, 1, 1, 1,
5662 1, 1, 1, 1, 1, 1, 1, 1,
5663};
5664
5665
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005666template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005667MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005668
5669
5670template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005671MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5672 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005673}
5674
5675
5676template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005677MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5678 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005679}
5680
5681
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005682template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005683static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5684 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005685 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005686 const Char* read_cursor = characters.start();
5687 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005688 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005689 int quoted_length = kSpaceForQuotes;
5690 while (read_cursor < end) {
5691 Char c = *(read_cursor++);
5692 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5693 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005694 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005695 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005696 }
5697 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005698 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5699 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005700 Object* new_object;
5701 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005702 return new_alloc;
5703 }
5704 StringType* new_string = StringType::cast(new_object);
5705
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005706 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005707 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005708 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005709 *(write_cursor++) = '"';
5710
5711 read_cursor = characters.start();
5712 while (read_cursor < end) {
5713 Char c = *(read_cursor++);
5714 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5715 *(write_cursor++) = c;
5716 } else {
5717 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5718 const char* replacement = JsonQuotes +
5719 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5720 for (int i = 0; i < len; i++) {
5721 *write_cursor++ = *replacement++;
5722 }
5723 }
5724 }
5725 *(write_cursor++) = '"';
5726 return new_string;
5727}
5728
5729
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005730template <typename SinkChar, typename SourceChar>
5731static inline SinkChar* WriteQuoteJsonString(
5732 Isolate* isolate,
5733 SinkChar* write_cursor,
5734 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005735 // SinkChar is only char if SourceChar is guaranteed to be char.
5736 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005737 const SourceChar* read_cursor = characters.start();
5738 const SourceChar* end = read_cursor + characters.length();
5739 *(write_cursor++) = '"';
5740 while (read_cursor < end) {
5741 SourceChar c = *(read_cursor++);
5742 if (sizeof(SourceChar) > 1u &&
5743 static_cast<unsigned>(c) >= kQuoteTableLength) {
5744 *(write_cursor++) = static_cast<SinkChar>(c);
5745 } else {
5746 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5747 const char* replacement = JsonQuotes +
5748 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5749 write_cursor[0] = replacement[0];
5750 if (len > 1) {
5751 write_cursor[1] = replacement[1];
5752 if (len > 2) {
5753 ASSERT(len == 6);
5754 write_cursor[2] = replacement[2];
5755 write_cursor[3] = replacement[3];
5756 write_cursor[4] = replacement[4];
5757 write_cursor[5] = replacement[5];
5758 }
5759 }
5760 write_cursor += len;
5761 }
5762 }
5763 *(write_cursor++) = '"';
5764 return write_cursor;
5765}
5766
5767
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005768template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005769static MaybeObject* QuoteJsonString(Isolate* isolate,
5770 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005771 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005772 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005773 int worst_case_length =
5774 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005775 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005776 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005777 }
5778
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005779 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5780 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005781 Object* new_object;
5782 if (!new_alloc->ToObject(&new_object)) {
5783 return new_alloc;
5784 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005785 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005786 // Even if our string is small enough to fit in new space we still have to
5787 // handle it being allocated in old space as may happen in the third
5788 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5789 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005790 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005791 }
5792 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005793 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005794
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005795 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005796 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005797 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005798 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5799 write_cursor,
5800 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005801 int final_length = static_cast<int>(
5802 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005803 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005804 isolate->heap()->new_space()->
5805 template ShrinkStringAtAllocationBoundary<StringType>(
5806 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005807 return new_string;
5808}
5809
5810
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005811RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005812 NoHandleAllocation ha;
5813 CONVERT_CHECKED(String, str, args[0]);
5814 if (!str->IsFlat()) {
5815 MaybeObject* try_flatten = str->TryFlatten();
5816 Object* flat;
5817 if (!try_flatten->ToObject(&flat)) {
5818 return try_flatten;
5819 }
5820 str = String::cast(flat);
5821 ASSERT(str->IsFlat());
5822 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005823 String::FlatContent flat = str->GetFlatContent();
5824 ASSERT(flat.IsFlat());
5825 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005826 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005827 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005828 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005829 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005830 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005831 }
5832}
5833
5834
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005835RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005836 NoHandleAllocation ha;
5837 CONVERT_CHECKED(String, str, args[0]);
5838 if (!str->IsFlat()) {
5839 MaybeObject* try_flatten = str->TryFlatten();
5840 Object* flat;
5841 if (!try_flatten->ToObject(&flat)) {
5842 return try_flatten;
5843 }
5844 str = String::cast(flat);
5845 ASSERT(str->IsFlat());
5846 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005847 String::FlatContent flat = str->GetFlatContent();
5848 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005849 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005850 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005851 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005852 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005853 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005854 }
5855}
5856
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005857
5858template <typename Char, typename StringType>
5859static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5860 FixedArray* array,
5861 int worst_case_length) {
5862 int length = array->length();
5863
5864 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5865 worst_case_length);
5866 Object* new_object;
5867 if (!new_alloc->ToObject(&new_object)) {
5868 return new_alloc;
5869 }
5870 if (!isolate->heap()->new_space()->Contains(new_object)) {
5871 // Even if our string is small enough to fit in new space we still have to
5872 // handle it being allocated in old space as may happen in the third
5873 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5874 // CEntryStub::GenerateCore.
5875 return isolate->heap()->undefined_value();
5876 }
5877 AssertNoAllocation no_gc;
5878 StringType* new_string = StringType::cast(new_object);
5879 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5880
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005881 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005882 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005883 *(write_cursor++) = '[';
5884 for (int i = 0; i < length; i++) {
5885 if (i != 0) *(write_cursor++) = ',';
5886 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005887 String::FlatContent content = str->GetFlatContent();
5888 ASSERT(content.IsFlat());
5889 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005890 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5891 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005892 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005893 } else {
5894 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5895 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005896 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005897 }
5898 }
5899 *(write_cursor++) = ']';
5900
5901 int final_length = static_cast<int>(
5902 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005903 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005904 isolate->heap()->new_space()->
5905 template ShrinkStringAtAllocationBoundary<StringType>(
5906 new_string, final_length);
5907 return new_string;
5908}
5909
5910
5911RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5912 NoHandleAllocation ha;
5913 ASSERT(args.length() == 1);
5914 CONVERT_CHECKED(JSArray, array, args[0]);
5915
5916 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5917 FixedArray* elements = FixedArray::cast(array->elements());
5918 int n = elements->length();
5919 bool ascii = true;
5920 int total_length = 0;
5921
5922 for (int i = 0; i < n; i++) {
5923 Object* elt = elements->get(i);
5924 if (!elt->IsString()) return isolate->heap()->undefined_value();
5925 String* element = String::cast(elt);
5926 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5927 total_length += element->length();
5928 if (ascii && element->IsTwoByteRepresentation()) {
5929 ascii = false;
5930 }
5931 }
5932
5933 int worst_case_length =
5934 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5935 + total_length * kJsonQuoteWorstCaseBlowup;
5936
5937 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5938 return isolate->heap()->undefined_value();
5939 }
5940
5941 if (ascii) {
5942 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5943 elements,
5944 worst_case_length);
5945 } else {
5946 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5947 elements,
5948 worst_case_length);
5949 }
5950}
5951
5952
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005953RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005954 NoHandleAllocation ha;
5955
5956 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005957 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005958
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005959 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005960
lrn@chromium.org25156de2010-04-06 13:10:27 +00005961 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005962 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005963 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005964}
5965
5966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005967RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005968 NoHandleAllocation ha;
5969 CONVERT_CHECKED(String, str, args[0]);
5970
5971 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005972 double value = StringToDouble(isolate->unicode_cache(),
5973 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005974
5975 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005976 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005977}
5978
5979
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005980template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005981MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005982 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005983 String* s,
5984 int length,
5985 int input_string_length,
5986 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005987 // We try this twice, once with the assumption that the result is no longer
5988 // than the input and, if that assumption breaks, again with the exact
5989 // length. This may not be pretty, but it is nicer than what was here before
5990 // and I hereby claim my vaffel-is.
5991 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005992 // Allocate the resulting string.
5993 //
5994 // NOTE: This assumes that the upper/lower case of an ascii
5995 // character is also ascii. This is currently the case, but it
5996 // might break in the future if we implement more context and locale
5997 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005998 Object* o;
5999 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006000 ? isolate->heap()->AllocateRawAsciiString(length)
6001 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006002 if (!maybe_o->ToObject(&o)) return maybe_o;
6003 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006004 String* result = String::cast(o);
6005 bool has_changed_character = false;
6006
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006007 // Convert all characters to upper case, assuming that they will fit
6008 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006009 Access<StringInputBuffer> buffer(
6010 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006011 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006012 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006013 // We can assume that the string is not empty
6014 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006015 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006016 bool has_next = buffer->has_more();
6017 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006018 int char_length = mapping->get(current, next, chars);
6019 if (char_length == 0) {
6020 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006021 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006022 i++;
6023 } else if (char_length == 1) {
6024 // Common case: converting the letter resulted in one character.
6025 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006026 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006027 has_changed_character = true;
6028 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006029 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006030 // We've assumed that the result would be as long as the
6031 // input but here is a character that converts to several
6032 // characters. No matter, we calculate the exact length
6033 // of the result and try the whole thing again.
6034 //
6035 // Note that this leaves room for optimization. We could just
6036 // memcpy what we already have to the result string. Also,
6037 // the result string is the last object allocated we could
6038 // "realloc" it and probably, in the vast majority of cases,
6039 // extend the existing string to be able to hold the full
6040 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006041 int next_length = 0;
6042 if (has_next) {
6043 next_length = mapping->get(next, 0, chars);
6044 if (next_length == 0) next_length = 1;
6045 }
6046 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006047 while (buffer->has_more()) {
6048 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006049 // NOTE: we use 0 as the next character here because, while
6050 // the next character may affect what a character converts to,
6051 // it does not in any case affect the length of what it convert
6052 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006053 int char_length = mapping->get(current, 0, chars);
6054 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006055 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006056 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006057 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006058 return Failure::OutOfMemoryException();
6059 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006060 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006061 // Try again with the real length.
6062 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006063 } else {
6064 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006065 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006066 i++;
6067 }
6068 has_changed_character = true;
6069 }
6070 current = next;
6071 }
6072 if (has_changed_character) {
6073 return result;
6074 } else {
6075 // If we didn't actually change anything in doing the conversion
6076 // we simple return the result and let the converted string
6077 // become garbage; there is no reason to keep two identical strings
6078 // alive.
6079 return s;
6080 }
6081}
6082
6083
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006084namespace {
6085
lrn@chromium.org303ada72010-10-27 09:33:13 +00006086static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6087
6088
6089// Given a word and two range boundaries returns a word with high bit
6090// set in every byte iff the corresponding input byte was strictly in
6091// the range (m, n). All the other bits in the result are cleared.
6092// This function is only useful when it can be inlined and the
6093// boundaries are statically known.
6094// Requires: all bytes in the input word and the boundaries must be
6095// ascii (less than 0x7F).
6096static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
6097 // Every byte in an ascii string is less than or equal to 0x7F.
6098 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6099 // Use strict inequalities since in edge cases the function could be
6100 // further simplified.
6101 ASSERT(0 < m && m < n && n < 0x7F);
6102 // Has high bit set in every w byte less than n.
6103 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6104 // Has high bit set in every w byte greater than m.
6105 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6106 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6107}
6108
6109
6110enum AsciiCaseConversion {
6111 ASCII_TO_LOWER,
6112 ASCII_TO_UPPER
6113};
6114
6115
6116template <AsciiCaseConversion dir>
6117struct FastAsciiConverter {
6118 static bool Convert(char* dst, char* src, int length) {
6119#ifdef DEBUG
6120 char* saved_dst = dst;
6121 char* saved_src = src;
6122#endif
6123 // We rely on the distance between upper and lower case letters
6124 // being a known power of 2.
6125 ASSERT('a' - 'A' == (1 << 5));
6126 // Boundaries for the range of input characters than require conversion.
6127 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6128 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6129 bool changed = false;
6130 char* const limit = src + length;
6131#ifdef V8_HOST_CAN_READ_UNALIGNED
6132 // Process the prefix of the input that requires no conversion one
6133 // (machine) word at a time.
6134 while (src <= limit - sizeof(uintptr_t)) {
6135 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6136 if (AsciiRangeMask(w, lo, hi) != 0) {
6137 changed = true;
6138 break;
6139 }
6140 *reinterpret_cast<uintptr_t*>(dst) = w;
6141 src += sizeof(uintptr_t);
6142 dst += sizeof(uintptr_t);
6143 }
6144 // Process the remainder of the input performing conversion when
6145 // required one word at a time.
6146 while (src <= limit - sizeof(uintptr_t)) {
6147 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6148 uintptr_t m = AsciiRangeMask(w, lo, hi);
6149 // The mask has high (7th) bit set in every byte that needs
6150 // conversion and we know that the distance between cases is
6151 // 1 << 5.
6152 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6153 src += sizeof(uintptr_t);
6154 dst += sizeof(uintptr_t);
6155 }
6156#endif
6157 // Process the last few bytes of the input (or the whole input if
6158 // unaligned access is not supported).
6159 while (src < limit) {
6160 char c = *src;
6161 if (lo < c && c < hi) {
6162 c ^= (1 << 5);
6163 changed = true;
6164 }
6165 *dst = c;
6166 ++src;
6167 ++dst;
6168 }
6169#ifdef DEBUG
6170 CheckConvert(saved_dst, saved_src, length, changed);
6171#endif
6172 return changed;
6173 }
6174
6175#ifdef DEBUG
6176 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6177 bool expected_changed = false;
6178 for (int i = 0; i < length; i++) {
6179 if (dst[i] == src[i]) continue;
6180 expected_changed = true;
6181 if (dir == ASCII_TO_LOWER) {
6182 ASSERT('A' <= src[i] && src[i] <= 'Z');
6183 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6184 } else {
6185 ASSERT(dir == ASCII_TO_UPPER);
6186 ASSERT('a' <= src[i] && src[i] <= 'z');
6187 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6188 }
6189 }
6190 ASSERT(expected_changed == changed);
6191 }
6192#endif
6193};
6194
6195
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006196struct ToLowerTraits {
6197 typedef unibrow::ToLowercase UnibrowConverter;
6198
lrn@chromium.org303ada72010-10-27 09:33:13 +00006199 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006200};
6201
6202
6203struct ToUpperTraits {
6204 typedef unibrow::ToUppercase UnibrowConverter;
6205
lrn@chromium.org303ada72010-10-27 09:33:13 +00006206 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006207};
6208
6209} // namespace
6210
6211
6212template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006213MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006214 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006215 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006216 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006217 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006218 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006219 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006220
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006221 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006222 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006223 if (length == 0) return s;
6224
6225 // Simpler handling of ascii strings.
6226 //
6227 // NOTE: This assumes that the upper/lower case of an ascii
6228 // character is also ascii. This is currently the case, but it
6229 // might break in the future if we implement more context and locale
6230 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006231 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006232 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006233 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006234 if (!maybe_o->ToObject(&o)) return maybe_o;
6235 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006236 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006237 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006238 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006239 return has_changed_character ? result : s;
6240 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006241
lrn@chromium.org303ada72010-10-27 09:33:13 +00006242 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006243 { MaybeObject* maybe_answer =
6244 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006245 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6246 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006247 if (answer->IsSmi()) {
6248 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006249 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006250 ConvertCaseHelper(isolate,
6251 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006252 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6253 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006254 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006255 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006256}
6257
6258
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006259RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006260 return ConvertCase<ToLowerTraits>(
6261 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006262}
6263
6264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006265RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006266 return ConvertCase<ToUpperTraits>(
6267 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006268}
6269
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006270
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006271static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006272 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006273}
6274
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006275
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006276RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006277 NoHandleAllocation ha;
6278 ASSERT(args.length() == 3);
6279
6280 CONVERT_CHECKED(String, s, args[0]);
6281 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6282 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6283
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006284 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006285 int length = s->length();
6286
6287 int left = 0;
6288 if (trimLeft) {
6289 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6290 left++;
6291 }
6292 }
6293
6294 int right = length;
6295 if (trimRight) {
6296 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6297 right--;
6298 }
6299 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006300 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006301}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006302
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006303
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006304RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006305 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006306 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006307 CONVERT_ARG_CHECKED(String, subject, 0);
6308 CONVERT_ARG_CHECKED(String, pattern, 1);
6309 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6310
6311 int subject_length = subject->length();
6312 int pattern_length = pattern->length();
6313 RUNTIME_ASSERT(pattern_length > 0);
6314
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006315 if (limit == 0xffffffffu) {
6316 Handle<Object> cached_answer(StringSplitCache::Lookup(
6317 isolate->heap()->string_split_cache(),
6318 *subject,
6319 *pattern));
6320 if (*cached_answer != Smi::FromInt(0)) {
6321 Handle<JSArray> result =
6322 isolate->factory()->NewJSArrayWithElements(
6323 Handle<FixedArray>::cast(cached_answer));
6324 return *result;
6325 }
6326 }
6327
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006328 // The limit can be very large (0xffffffffu), but since the pattern
6329 // isn't empty, we can never create more parts than ~half the length
6330 // of the subject.
6331
6332 if (!subject->IsFlat()) FlattenString(subject);
6333
6334 static const int kMaxInitialListCapacity = 16;
6335
danno@chromium.org40cb8782011-05-25 07:58:50 +00006336 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006337
6338 // Find (up to limit) indices of separator and end-of-string in subject
6339 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6340 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006341 if (!pattern->IsFlat()) FlattenString(pattern);
6342
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006343 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006344
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006345 if (static_cast<uint32_t>(indices.length()) < limit) {
6346 indices.Add(subject_length);
6347 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006348
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006349 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006350
6351 // Create JSArray of substrings separated by separator.
6352 int part_count = indices.length();
6353
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006354 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006355 MaybeObject* maybe_result = result->EnsureCanContainNonSmiElements();
6356 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006357 result->set_length(Smi::FromInt(part_count));
6358
6359 ASSERT(result->HasFastElements());
6360
6361 if (part_count == 1 && indices.at(0) == subject_length) {
6362 FixedArray::cast(result->elements())->set(0, *subject);
6363 return *result;
6364 }
6365
6366 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6367 int part_start = 0;
6368 for (int i = 0; i < part_count; i++) {
6369 HandleScope local_loop_handle;
6370 int part_end = indices.at(i);
6371 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006372 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006373 elements->set(i, *substring);
6374 part_start = part_end + pattern_length;
6375 }
6376
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006377 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006378 if (result->HasFastElements()) {
6379 StringSplitCache::Enter(isolate->heap(),
6380 isolate->heap()->string_split_cache(),
6381 *subject,
6382 *pattern,
6383 *elements);
6384 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006385 }
6386
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006387 return *result;
6388}
6389
6390
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006391// Copies ascii characters to the given fixed array looking up
6392// one-char strings in the cache. Gives up on the first char that is
6393// not in the cache and fills the remainder with smi zeros. Returns
6394// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006395static int CopyCachedAsciiCharsToArray(Heap* heap,
6396 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006397 FixedArray* elements,
6398 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006399 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006400 FixedArray* ascii_cache = heap->single_character_string_cache();
6401 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006402 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006403 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006404 for (i = 0; i < length; ++i) {
6405 Object* value = ascii_cache->get(chars[i]);
6406 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006407 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006408 }
6409 if (i < length) {
6410 ASSERT(Smi::FromInt(0) == 0);
6411 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6412 }
6413#ifdef DEBUG
6414 for (int j = 0; j < length; ++j) {
6415 Object* element = elements->get(j);
6416 ASSERT(element == Smi::FromInt(0) ||
6417 (element->IsString() && String::cast(element)->LooksValid()));
6418 }
6419#endif
6420 return i;
6421}
6422
6423
6424// Converts a String to JSArray.
6425// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006426RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006427 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006428 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006429 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006430 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006431
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006432 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006433 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006434
6435 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006436 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006437 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006438 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006439 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006440 { MaybeObject* maybe_obj =
6441 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006442 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6443 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006444 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006445 String::FlatContent content = s->GetFlatContent();
6446 if (content.IsAscii()) {
6447 Vector<const char> chars = content.ToAsciiVector();
6448 // Note, this will initialize all elements (not only the prefix)
6449 // to prevent GC from seeing partially initialized array.
6450 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6451 chars.start(),
6452 *elements,
6453 length);
6454 } else {
6455 MemsetPointer(elements->data_start(),
6456 isolate->heap()->undefined_value(),
6457 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006458 }
6459 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006460 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006461 }
6462 for (int i = position; i < length; ++i) {
6463 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6464 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006465 }
6466
6467#ifdef DEBUG
6468 for (int i = 0; i < length; ++i) {
6469 ASSERT(String::cast(elements->get(i))->length() == 1);
6470 }
6471#endif
6472
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006473 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006474}
6475
6476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006477RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006478 NoHandleAllocation ha;
6479 ASSERT(args.length() == 1);
6480 CONVERT_CHECKED(String, value, args[0]);
6481 return value->ToObject();
6482}
6483
6484
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006485bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006486 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006487 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006488 return char_length == 0;
6489}
6490
6491
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006492RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006493 NoHandleAllocation ha;
6494 ASSERT(args.length() == 1);
6495
6496 Object* number = args[0];
6497 RUNTIME_ASSERT(number->IsNumber());
6498
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006499 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006500}
6501
6502
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006503RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006504 NoHandleAllocation ha;
6505 ASSERT(args.length() == 1);
6506
6507 Object* number = args[0];
6508 RUNTIME_ASSERT(number->IsNumber());
6509
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006510 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006511}
6512
6513
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006514RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006515 NoHandleAllocation ha;
6516 ASSERT(args.length() == 1);
6517
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006518 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006519
6520 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6521 if (number > 0 && number <= Smi::kMaxValue) {
6522 return Smi::FromInt(static_cast<int>(number));
6523 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006524 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006525}
6526
6527
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006528RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006529 NoHandleAllocation ha;
6530 ASSERT(args.length() == 1);
6531
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006532 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006533
6534 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6535 if (number > 0 && number <= Smi::kMaxValue) {
6536 return Smi::FromInt(static_cast<int>(number));
6537 }
6538
6539 double double_value = DoubleToInteger(number);
6540 // Map both -0 and +0 to +0.
6541 if (double_value == 0) double_value = 0;
6542
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006543 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006544}
6545
6546
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006547RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006548 NoHandleAllocation ha;
6549 ASSERT(args.length() == 1);
6550
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006551 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006552 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006553}
6554
6555
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006556RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006557 NoHandleAllocation ha;
6558 ASSERT(args.length() == 1);
6559
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006560 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006561
6562 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6563 if (number > 0 && number <= Smi::kMaxValue) {
6564 return Smi::FromInt(static_cast<int>(number));
6565 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006566 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006567}
6568
6569
ager@chromium.org870a0b62008-11-04 11:43:05 +00006570// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6571// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006572RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006573 NoHandleAllocation ha;
6574 ASSERT(args.length() == 1);
6575
6576 Object* obj = args[0];
6577 if (obj->IsSmi()) {
6578 return obj;
6579 }
6580 if (obj->IsHeapNumber()) {
6581 double value = HeapNumber::cast(obj)->value();
6582 int int_value = FastD2I(value);
6583 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6584 return Smi::FromInt(int_value);
6585 }
6586 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006587 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006588}
6589
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006590
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006591RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006592 NoHandleAllocation ha;
6593 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006594 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006595}
6596
6597
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006598RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006599 NoHandleAllocation ha;
6600 ASSERT(args.length() == 2);
6601
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006602 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6603 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006604 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006605}
6606
6607
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006608RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006609 NoHandleAllocation ha;
6610 ASSERT(args.length() == 2);
6611
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006612 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6613 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006614 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006615}
6616
6617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006618RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006619 NoHandleAllocation ha;
6620 ASSERT(args.length() == 2);
6621
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006622 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6623 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006624 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006625}
6626
6627
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006628RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006629 NoHandleAllocation ha;
6630 ASSERT(args.length() == 1);
6631
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006632 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006633 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006634}
6635
6636
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006637RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006638 NoHandleAllocation ha;
6639 ASSERT(args.length() == 0);
6640
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006641 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006642}
6643
6644
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006645RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006646 NoHandleAllocation ha;
6647 ASSERT(args.length() == 2);
6648
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006649 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6650 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006651 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652}
6653
6654
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006655RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006656 NoHandleAllocation ha;
6657 ASSERT(args.length() == 2);
6658
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006659 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6660 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006661
ager@chromium.org3811b432009-10-28 14:53:37 +00006662 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006663 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006664 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006665}
6666
6667
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006668RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006669 NoHandleAllocation ha;
6670 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006671 CONVERT_CHECKED(String, str1, args[0]);
6672 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006673 isolate->counters()->string_add_runtime()->Increment();
6674 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006675}
6676
6677
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006678template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006679static inline void StringBuilderConcatHelper(String* special,
6680 sinkchar* sink,
6681 FixedArray* fixed_array,
6682 int array_length) {
6683 int position = 0;
6684 for (int i = 0; i < array_length; i++) {
6685 Object* element = fixed_array->get(i);
6686 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006687 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006688 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006689 int pos;
6690 int len;
6691 if (encoded_slice > 0) {
6692 // Position and length encoded in one smi.
6693 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6694 len = StringBuilderSubstringLength::decode(encoded_slice);
6695 } else {
6696 // Position and length encoded in two smis.
6697 Object* obj = fixed_array->get(++i);
6698 ASSERT(obj->IsSmi());
6699 pos = Smi::cast(obj)->value();
6700 len = -encoded_slice;
6701 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006702 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006703 sink + position,
6704 pos,
6705 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006706 position += len;
6707 } else {
6708 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006709 int element_length = string->length();
6710 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006711 position += element_length;
6712 }
6713 }
6714}
6715
6716
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006717RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006718 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006719 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006720 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006721 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006722 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006723 return Failure::OutOfMemoryException();
6724 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006725 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006726 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006727
6728 // This assumption is used by the slice encoding in one or two smis.
6729 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6730
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006731 MaybeObject* maybe_result = array->EnsureCanContainNonSmiElements();
6732 if (maybe_result->IsFailure()) return maybe_result;
6733
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006734 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006735 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006736 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006737 }
6738 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006739 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006740 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006741 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006742
6743 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006744 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006745 } else if (array_length == 1) {
6746 Object* first = fixed_array->get(0);
6747 if (first->IsString()) return first;
6748 }
6749
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006750 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006751 int position = 0;
6752 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006753 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006754 Object* elt = fixed_array->get(i);
6755 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006756 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006757 int smi_value = Smi::cast(elt)->value();
6758 int pos;
6759 int len;
6760 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006761 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006762 pos = StringBuilderSubstringPosition::decode(smi_value);
6763 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006764 } else {
6765 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006766 len = -smi_value;
6767 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006768 i++;
6769 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006770 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006771 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006772 Object* next_smi = fixed_array->get(i);
6773 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006774 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006775 }
6776 pos = Smi::cast(next_smi)->value();
6777 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006778 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006779 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006780 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006781 ASSERT(pos >= 0);
6782 ASSERT(len >= 0);
6783 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006784 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006785 }
6786 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006787 } else if (elt->IsString()) {
6788 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006789 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006790 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006791 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006792 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006793 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006794 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006795 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006796 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006797 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006798 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006799 return Failure::OutOfMemoryException();
6800 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006801 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006802 }
6803
6804 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006805 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006806
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006807 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006808 { MaybeObject* maybe_object =
6809 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006810 if (!maybe_object->ToObject(&object)) return maybe_object;
6811 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006812 SeqAsciiString* answer = SeqAsciiString::cast(object);
6813 StringBuilderConcatHelper(special,
6814 answer->GetChars(),
6815 fixed_array,
6816 array_length);
6817 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006818 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006819 { MaybeObject* maybe_object =
6820 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006821 if (!maybe_object->ToObject(&object)) return maybe_object;
6822 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006823 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6824 StringBuilderConcatHelper(special,
6825 answer->GetChars(),
6826 fixed_array,
6827 array_length);
6828 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006829 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006830}
6831
6832
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006833RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006834 NoHandleAllocation ha;
6835 ASSERT(args.length() == 3);
6836 CONVERT_CHECKED(JSArray, array, args[0]);
6837 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006838 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006839 return Failure::OutOfMemoryException();
6840 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006841 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006842 CONVERT_CHECKED(String, separator, args[2]);
6843
6844 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006845 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006846 }
6847 FixedArray* fixed_array = FixedArray::cast(array->elements());
6848 if (fixed_array->length() < array_length) {
6849 array_length = fixed_array->length();
6850 }
6851
6852 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006853 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006854 } else if (array_length == 1) {
6855 Object* first = fixed_array->get(0);
6856 if (first->IsString()) return first;
6857 }
6858
6859 int separator_length = separator->length();
6860 int max_nof_separators =
6861 (String::kMaxLength + separator_length - 1) / separator_length;
6862 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006863 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006864 return Failure::OutOfMemoryException();
6865 }
6866 int length = (array_length - 1) * separator_length;
6867 for (int i = 0; i < array_length; i++) {
6868 Object* element_obj = fixed_array->get(i);
6869 if (!element_obj->IsString()) {
6870 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006871 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006872 }
6873 String* element = String::cast(element_obj);
6874 int increment = element->length();
6875 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006876 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006877 return Failure::OutOfMemoryException();
6878 }
6879 length += increment;
6880 }
6881
6882 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006883 { MaybeObject* maybe_object =
6884 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006885 if (!maybe_object->ToObject(&object)) return maybe_object;
6886 }
6887 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6888
6889 uc16* sink = answer->GetChars();
6890#ifdef DEBUG
6891 uc16* end = sink + length;
6892#endif
6893
6894 String* first = String::cast(fixed_array->get(0));
6895 int first_length = first->length();
6896 String::WriteToFlat(first, sink, 0, first_length);
6897 sink += first_length;
6898
6899 for (int i = 1; i < array_length; i++) {
6900 ASSERT(sink + separator_length <= end);
6901 String::WriteToFlat(separator, sink, 0, separator_length);
6902 sink += separator_length;
6903
6904 String* element = String::cast(fixed_array->get(i));
6905 int element_length = element->length();
6906 ASSERT(sink + element_length <= end);
6907 String::WriteToFlat(element, sink, 0, element_length);
6908 sink += element_length;
6909 }
6910 ASSERT(sink == end);
6911
6912 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6913 return answer;
6914}
6915
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006916template <typename Char>
6917static void JoinSparseArrayWithSeparator(FixedArray* elements,
6918 int elements_length,
6919 uint32_t array_length,
6920 String* separator,
6921 Vector<Char> buffer) {
6922 int previous_separator_position = 0;
6923 int separator_length = separator->length();
6924 int cursor = 0;
6925 for (int i = 0; i < elements_length; i += 2) {
6926 int position = NumberToInt32(elements->get(i));
6927 String* string = String::cast(elements->get(i + 1));
6928 int string_length = string->length();
6929 if (string->length() > 0) {
6930 while (previous_separator_position < position) {
6931 String::WriteToFlat<Char>(separator, &buffer[cursor],
6932 0, separator_length);
6933 cursor += separator_length;
6934 previous_separator_position++;
6935 }
6936 String::WriteToFlat<Char>(string, &buffer[cursor],
6937 0, string_length);
6938 cursor += string->length();
6939 }
6940 }
6941 if (separator_length > 0) {
6942 // Array length must be representable as a signed 32-bit number,
6943 // otherwise the total string length would have been too large.
6944 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6945 int last_array_index = static_cast<int>(array_length - 1);
6946 while (previous_separator_position < last_array_index) {
6947 String::WriteToFlat<Char>(separator, &buffer[cursor],
6948 0, separator_length);
6949 cursor += separator_length;
6950 previous_separator_position++;
6951 }
6952 }
6953 ASSERT(cursor <= buffer.length());
6954}
6955
6956
6957RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6958 NoHandleAllocation ha;
6959 ASSERT(args.length() == 3);
6960 CONVERT_CHECKED(JSArray, elements_array, args[0]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006961 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6962 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006963 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6964 CONVERT_CHECKED(String, separator, args[2]);
6965 // elements_array is fast-mode JSarray of alternating positions
6966 // (increasing order) and strings.
6967 // array_length is length of original array (used to add separators);
6968 // separator is string to put between elements. Assumed to be non-empty.
6969
6970 // Find total length of join result.
6971 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006972 bool is_ascii = separator->IsAsciiRepresentation();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006973 int max_string_length = SeqAsciiString::kMaxLength;
6974 bool overflow = false;
6975 CONVERT_NUMBER_CHECKED(int, elements_length,
6976 Int32, elements_array->length());
6977 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6978 FixedArray* elements = FixedArray::cast(elements_array->elements());
6979 for (int i = 0; i < elements_length; i += 2) {
6980 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6981 CONVERT_CHECKED(String, string, elements->get(i + 1));
6982 int length = string->length();
6983 if (is_ascii && !string->IsAsciiRepresentation()) {
6984 is_ascii = false;
6985 max_string_length = SeqTwoByteString::kMaxLength;
6986 }
6987 if (length > max_string_length ||
6988 max_string_length - length < string_length) {
6989 overflow = true;
6990 break;
6991 }
6992 string_length += length;
6993 }
6994 int separator_length = separator->length();
6995 if (!overflow && separator_length > 0) {
6996 if (array_length <= 0x7fffffffu) {
6997 int separator_count = static_cast<int>(array_length) - 1;
6998 int remaining_length = max_string_length - string_length;
6999 if ((remaining_length / separator_length) >= separator_count) {
7000 string_length += separator_length * (array_length - 1);
7001 } else {
7002 // Not room for the separators within the maximal string length.
7003 overflow = true;
7004 }
7005 } else {
7006 // Nonempty separator and at least 2^31-1 separators necessary
7007 // means that the string is too large to create.
7008 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
7009 overflow = true;
7010 }
7011 }
7012 if (overflow) {
7013 // Throw OutOfMemory exception for creating too large a string.
7014 V8::FatalProcessOutOfMemory("Array join result too large.");
7015 }
7016
7017 if (is_ascii) {
7018 MaybeObject* result_allocation =
7019 isolate->heap()->AllocateRawAsciiString(string_length);
7020 if (result_allocation->IsFailure()) return result_allocation;
7021 SeqAsciiString* result_string =
7022 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
7023 JoinSparseArrayWithSeparator<char>(elements,
7024 elements_length,
7025 array_length,
7026 separator,
7027 Vector<char>(result_string->GetChars(),
7028 string_length));
7029 return result_string;
7030 } else {
7031 MaybeObject* result_allocation =
7032 isolate->heap()->AllocateRawTwoByteString(string_length);
7033 if (result_allocation->IsFailure()) return result_allocation;
7034 SeqTwoByteString* result_string =
7035 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7036 JoinSparseArrayWithSeparator<uc16>(elements,
7037 elements_length,
7038 array_length,
7039 separator,
7040 Vector<uc16>(result_string->GetChars(),
7041 string_length));
7042 return result_string;
7043 }
7044}
7045
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007046
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007047RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007048 NoHandleAllocation ha;
7049 ASSERT(args.length() == 2);
7050
7051 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7052 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007053 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007054}
7055
7056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007057RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007058 NoHandleAllocation ha;
7059 ASSERT(args.length() == 2);
7060
7061 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7062 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007063 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007064}
7065
7066
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007067RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007068 NoHandleAllocation ha;
7069 ASSERT(args.length() == 2);
7070
7071 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7072 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007073 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007074}
7075
7076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007077RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007078 NoHandleAllocation ha;
7079 ASSERT(args.length() == 1);
7080
7081 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007082 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007083}
7084
7085
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007086RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007087 NoHandleAllocation ha;
7088 ASSERT(args.length() == 2);
7089
7090 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7091 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007092 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007093}
7094
7095
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007096RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007097 NoHandleAllocation ha;
7098 ASSERT(args.length() == 2);
7099
7100 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7101 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007102 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007103}
7104
7105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007106RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007107 NoHandleAllocation ha;
7108 ASSERT(args.length() == 2);
7109
7110 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7111 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007112 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007113}
7114
7115
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007116RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007117 NoHandleAllocation ha;
7118 ASSERT(args.length() == 2);
7119
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007120 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7121 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007122 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7123 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7124 if (x == y) return Smi::FromInt(EQUAL);
7125 Object* result;
7126 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7127 result = Smi::FromInt(EQUAL);
7128 } else {
7129 result = Smi::FromInt(NOT_EQUAL);
7130 }
7131 return result;
7132}
7133
7134
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007135RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007136 NoHandleAllocation ha;
7137 ASSERT(args.length() == 2);
7138
7139 CONVERT_CHECKED(String, x, args[0]);
7140 CONVERT_CHECKED(String, y, args[1]);
7141
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007142 bool not_equal = !x->Equals(y);
7143 // This is slightly convoluted because the value that signifies
7144 // equality is 0 and inequality is 1 so we have to negate the result
7145 // from String::Equals.
7146 ASSERT(not_equal == 0 || not_equal == 1);
7147 STATIC_CHECK(EQUAL == 0);
7148 STATIC_CHECK(NOT_EQUAL == 1);
7149 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007150}
7151
7152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007153RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007154 NoHandleAllocation ha;
7155 ASSERT(args.length() == 3);
7156
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007157 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7158 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007159 if (isnan(x) || isnan(y)) return args[2];
7160 if (x == y) return Smi::FromInt(EQUAL);
7161 if (isless(x, y)) return Smi::FromInt(LESS);
7162 return Smi::FromInt(GREATER);
7163}
7164
7165
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007166// Compare two Smis as if they were converted to strings and then
7167// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007168RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007169 NoHandleAllocation ha;
7170 ASSERT(args.length() == 2);
7171
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007172 // Extract the integer values from the Smis.
7173 CONVERT_CHECKED(Smi, x, args[0]);
7174 CONVERT_CHECKED(Smi, y, args[1]);
7175 int x_value = x->value();
7176 int y_value = y->value();
7177
7178 // If the integers are equal so are the string representations.
7179 if (x_value == y_value) return Smi::FromInt(EQUAL);
7180
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007181 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007182 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007183 if (x_value == 0 || y_value == 0)
7184 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007185
ager@chromium.org32912102009-01-16 10:38:43 +00007186 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007187 // smallest because the char code of '-' is less than the char code
7188 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007189
7190 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7191 // architectures using 32-bit Smis.
7192 uint32_t x_scaled = x_value;
7193 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007194 if (x_value < 0 || y_value < 0) {
7195 if (y_value >= 0) return Smi::FromInt(LESS);
7196 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007197 x_scaled = -x_value;
7198 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007199 }
7200
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007201 static const uint32_t kPowersOf10[] = {
7202 1, 10, 100, 1000, 10*1000, 100*1000,
7203 1000*1000, 10*1000*1000, 100*1000*1000,
7204 1000*1000*1000
7205 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007206
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007207 // If the integers have the same number of decimal digits they can be
7208 // compared directly as the numeric order is the same as the
7209 // lexicographic order. If one integer has fewer digits, it is scaled
7210 // by some power of 10 to have the same number of digits as the longer
7211 // integer. If the scaled integers are equal it means the shorter
7212 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007213
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007214 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7215 int x_log2 = IntegerLog2(x_scaled);
7216 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7217 x_log10 -= x_scaled < kPowersOf10[x_log10];
7218
7219 int y_log2 = IntegerLog2(y_scaled);
7220 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7221 y_log10 -= y_scaled < kPowersOf10[y_log10];
7222
7223 int tie = EQUAL;
7224
7225 if (x_log10 < y_log10) {
7226 // X has fewer digits. We would like to simply scale up X but that
7227 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7228 // be scaled up to 9_000_000_000. So we scale up by the next
7229 // smallest power and scale down Y to drop one digit. It is OK to
7230 // drop one digit from the longer integer since the final digit is
7231 // past the length of the shorter integer.
7232 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7233 y_scaled /= 10;
7234 tie = LESS;
7235 } else if (y_log10 < x_log10) {
7236 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7237 x_scaled /= 10;
7238 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007239 }
7240
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007241 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7242 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7243 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007244}
7245
7246
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007247static Object* StringInputBufferCompare(RuntimeState* state,
7248 String* x,
7249 String* y) {
7250 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7251 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007252 bufx.Reset(x);
7253 bufy.Reset(y);
7254 while (bufx.has_more() && bufy.has_more()) {
7255 int d = bufx.GetNext() - bufy.GetNext();
7256 if (d < 0) return Smi::FromInt(LESS);
7257 else if (d > 0) return Smi::FromInt(GREATER);
7258 }
7259
7260 // x is (non-trivial) prefix of y:
7261 if (bufy.has_more()) return Smi::FromInt(LESS);
7262 // y is prefix of x:
7263 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7264}
7265
7266
7267static Object* FlatStringCompare(String* x, String* y) {
7268 ASSERT(x->IsFlat());
7269 ASSERT(y->IsFlat());
7270 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7271 int prefix_length = x->length();
7272 if (y->length() < prefix_length) {
7273 prefix_length = y->length();
7274 equal_prefix_result = Smi::FromInt(GREATER);
7275 } else if (y->length() > prefix_length) {
7276 equal_prefix_result = Smi::FromInt(LESS);
7277 }
7278 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007279 String::FlatContent x_content = x->GetFlatContent();
7280 String::FlatContent y_content = y->GetFlatContent();
7281 if (x_content.IsAscii()) {
7282 Vector<const char> x_chars = x_content.ToAsciiVector();
7283 if (y_content.IsAscii()) {
7284 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007285 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007286 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007287 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007288 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7289 }
7290 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007291 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7292 if (y_content.IsAscii()) {
7293 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007294 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7295 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007296 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007297 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7298 }
7299 }
7300 Object* result;
7301 if (r == 0) {
7302 result = equal_prefix_result;
7303 } else {
7304 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7305 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007306 ASSERT(result ==
7307 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007308 return result;
7309}
7310
7311
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007312RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007313 NoHandleAllocation ha;
7314 ASSERT(args.length() == 2);
7315
7316 CONVERT_CHECKED(String, x, args[0]);
7317 CONVERT_CHECKED(String, y, args[1]);
7318
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007319 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007320
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007321 // A few fast case tests before we flatten.
7322 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007323 if (y->length() == 0) {
7324 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007325 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007326 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007327 return Smi::FromInt(LESS);
7328 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007329
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007330 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007331 if (d < 0) return Smi::FromInt(LESS);
7332 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007333
lrn@chromium.org303ada72010-10-27 09:33:13 +00007334 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007335 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007336 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7337 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007338 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007339 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7340 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007341
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007342 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007343 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007344}
7345
7346
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007347RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007348 NoHandleAllocation ha;
7349 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007350 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007351
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007352 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007353 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007354}
7355
7356
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007357RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007358 NoHandleAllocation ha;
7359 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007360 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007361
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007362 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007363 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007364}
7365
7366
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007367RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007368 NoHandleAllocation ha;
7369 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007370 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007371
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007372 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007373 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007374}
7375
7376
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007377static const double kPiDividedBy4 = 0.78539816339744830962;
7378
7379
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007380RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007381 NoHandleAllocation ha;
7382 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007383 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007384
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007385 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7386 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007387 double result;
7388 if (isinf(x) && isinf(y)) {
7389 // Make sure that the result in case of two infinite arguments
7390 // is a multiple of Pi / 4. The sign of the result is determined
7391 // by the first argument (x) and the sign of the second argument
7392 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007393 int multiplier = (x < 0) ? -1 : 1;
7394 if (y < 0) multiplier *= 3;
7395 result = multiplier * kPiDividedBy4;
7396 } else {
7397 result = atan2(x, y);
7398 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007399 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007400}
7401
7402
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007403RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007404 NoHandleAllocation ha;
7405 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007406 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007407
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007408 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007409 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007410}
7411
7412
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007413RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007414 NoHandleAllocation ha;
7415 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007416 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007417
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007418 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007419 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007420}
7421
7422
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007423RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007424 NoHandleAllocation ha;
7425 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007426 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007427
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007428 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007429 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007430}
7431
7432
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007433RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007434 NoHandleAllocation ha;
7435 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007436 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007437
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007438 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007439 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007440}
7441
7442
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007443RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007444 NoHandleAllocation ha;
7445 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007446 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007447
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007448 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007449 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007450}
7451
7452
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007453RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007454 NoHandleAllocation ha;
7455 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007456 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007457
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007458 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007459
7460 // If the second argument is a smi, it is much faster to call the
7461 // custom powi() function than the generic pow().
7462 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007463 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007464 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007465 }
7466
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007467 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007468 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007469}
7470
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007471// Fast version of Math.pow if we know that y is not an integer and
7472// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007473RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007474 NoHandleAllocation ha;
7475 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007476 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7477 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007478 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007479 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007480 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007481 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007482 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007483 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007484 }
7485}
7486
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007488RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007489 NoHandleAllocation ha;
7490 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007491 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007492
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007493 if (!args[0]->IsHeapNumber()) {
7494 // Must be smi. Return the argument unchanged for all the other types
7495 // to make fuzz-natives test happy.
7496 return args[0];
7497 }
7498
7499 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7500
7501 double value = number->value();
7502 int exponent = number->get_exponent();
7503 int sign = number->get_sign();
7504
danno@chromium.org160a7b02011-04-18 15:51:38 +00007505 if (exponent < -1) {
7506 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7507 if (sign) return isolate->heap()->minus_zero_value();
7508 return Smi::FromInt(0);
7509 }
7510
7511 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7512 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7513 // agument holds for 32-bit smis).
7514 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007515 return Smi::FromInt(static_cast<int>(value + 0.5));
7516 }
7517
7518 // If the magnitude is big enough, there's no place for fraction part. If we
7519 // try to add 0.5 to this number, 1.0 will be added instead.
7520 if (exponent >= 52) {
7521 return number;
7522 }
7523
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007524 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007525
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007526 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007527 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007528}
7529
7530
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007531RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
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_sin()->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::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007538}
7539
7540
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007541RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007542 NoHandleAllocation ha;
7543 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007544 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007545
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007546 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007547 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007548}
7549
7550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007551RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007552 NoHandleAllocation ha;
7553 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007554 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007555
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007556 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007557 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007558}
7559
7560
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007561static int MakeDay(int year, int month) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007562 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7563 181, 212, 243, 273, 304, 334};
7564 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7565 182, 213, 244, 274, 305, 335};
7566
7567 year += month / 12;
7568 month %= 12;
7569 if (month < 0) {
7570 year--;
7571 month += 12;
7572 }
7573
7574 ASSERT(month >= 0);
7575 ASSERT(month < 12);
7576
7577 // year_delta is an arbitrary number such that:
7578 // a) year_delta = -1 (mod 400)
7579 // b) year + year_delta > 0 for years in the range defined by
7580 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7581 // Jan 1 1970. This is required so that we don't run into integer
7582 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007583 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007584 // operations.
7585 static const int year_delta = 399999;
7586 static const int base_day = 365 * (1970 + year_delta) +
7587 (1970 + year_delta) / 4 -
7588 (1970 + year_delta) / 100 +
7589 (1970 + year_delta) / 400;
7590
7591 int year1 = year + year_delta;
7592 int day_from_year = 365 * year1 +
7593 year1 / 4 -
7594 year1 / 100 +
7595 year1 / 400 -
7596 base_day;
7597
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007598 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
7599 return day_from_year + day_from_month[month];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007600 }
7601
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007602 return day_from_year + day_from_month_leap[month];
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007603}
7604
7605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007606RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007607 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007608 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007609
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007610 CONVERT_SMI_ARG_CHECKED(year, 0);
7611 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007612
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007613 return Smi::FromInt(MakeDay(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007614}
7615
7616
7617static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7618static const int kDaysIn4Years = 4 * 365 + 1;
7619static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7620static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7621static const int kDays1970to2000 = 30 * 365 + 7;
7622static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7623 kDays1970to2000;
7624static const int kYearsOffset = 400000;
7625
7626static const char kDayInYear[] = {
7627 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7628 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7629 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7630 22, 23, 24, 25, 26, 27, 28,
7631 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7632 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7633 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7634 22, 23, 24, 25, 26, 27, 28, 29, 30,
7635 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7636 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7637 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7638 22, 23, 24, 25, 26, 27, 28, 29, 30,
7639 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7640 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7641 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7642 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7643 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7644 22, 23, 24, 25, 26, 27, 28, 29, 30,
7645 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7646 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7647 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7648 22, 23, 24, 25, 26, 27, 28, 29, 30,
7649 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7650 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7651
7652 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7653 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7654 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7655 22, 23, 24, 25, 26, 27, 28,
7656 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7657 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7658 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7659 22, 23, 24, 25, 26, 27, 28, 29, 30,
7660 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7661 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7662 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7663 22, 23, 24, 25, 26, 27, 28, 29, 30,
7664 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7665 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7666 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7667 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7668 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7669 22, 23, 24, 25, 26, 27, 28, 29, 30,
7670 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7671 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7672 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7673 22, 23, 24, 25, 26, 27, 28, 29, 30,
7674 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7675 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7676
7677 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7678 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7679 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7680 22, 23, 24, 25, 26, 27, 28, 29,
7681 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7682 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7683 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7684 22, 23, 24, 25, 26, 27, 28, 29, 30,
7685 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7686 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7687 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7688 22, 23, 24, 25, 26, 27, 28, 29, 30,
7689 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7690 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7691 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7692 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7693 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7694 22, 23, 24, 25, 26, 27, 28, 29, 30,
7695 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7696 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7697 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7698 22, 23, 24, 25, 26, 27, 28, 29, 30,
7699 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7700 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7701
7702 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7703 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7704 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7705 22, 23, 24, 25, 26, 27, 28,
7706 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7707 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7708 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7709 22, 23, 24, 25, 26, 27, 28, 29, 30,
7710 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7711 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7712 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7713 22, 23, 24, 25, 26, 27, 28, 29, 30,
7714 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7715 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7716 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7717 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7718 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7719 22, 23, 24, 25, 26, 27, 28, 29, 30,
7720 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7721 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7722 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7723 22, 23, 24, 25, 26, 27, 28, 29, 30,
7724 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7725 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7726
7727static const char kMonthInYear[] = {
7728 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7729 0, 0, 0, 0, 0, 0,
7730 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7731 1, 1, 1,
7732 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7733 2, 2, 2, 2, 2, 2,
7734 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7735 3, 3, 3, 3, 3,
7736 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7737 4, 4, 4, 4, 4, 4,
7738 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7739 5, 5, 5, 5, 5,
7740 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7741 6, 6, 6, 6, 6, 6,
7742 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7743 7, 7, 7, 7, 7, 7,
7744 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7745 8, 8, 8, 8, 8,
7746 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7747 9, 9, 9, 9, 9, 9,
7748 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7749 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7750 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7751 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7752
7753 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7754 0, 0, 0, 0, 0, 0,
7755 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7756 1, 1, 1,
7757 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7758 2, 2, 2, 2, 2, 2,
7759 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7760 3, 3, 3, 3, 3,
7761 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7762 4, 4, 4, 4, 4, 4,
7763 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7764 5, 5, 5, 5, 5,
7765 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7766 6, 6, 6, 6, 6, 6,
7767 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7768 7, 7, 7, 7, 7, 7,
7769 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7770 8, 8, 8, 8, 8,
7771 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7772 9, 9, 9, 9, 9, 9,
7773 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7774 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7775 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7776 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7777
7778 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7779 0, 0, 0, 0, 0, 0,
7780 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7781 1, 1, 1, 1,
7782 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7783 2, 2, 2, 2, 2, 2,
7784 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7785 3, 3, 3, 3, 3,
7786 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7787 4, 4, 4, 4, 4, 4,
7788 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7789 5, 5, 5, 5, 5,
7790 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7791 6, 6, 6, 6, 6, 6,
7792 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7793 7, 7, 7, 7, 7, 7,
7794 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7795 8, 8, 8, 8, 8,
7796 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7797 9, 9, 9, 9, 9, 9,
7798 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7799 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7800 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7801 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7802
7803 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7804 0, 0, 0, 0, 0, 0,
7805 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7806 1, 1, 1,
7807 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7808 2, 2, 2, 2, 2, 2,
7809 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7810 3, 3, 3, 3, 3,
7811 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7812 4, 4, 4, 4, 4, 4,
7813 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7814 5, 5, 5, 5, 5,
7815 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7816 6, 6, 6, 6, 6, 6,
7817 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7818 7, 7, 7, 7, 7, 7,
7819 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7820 8, 8, 8, 8, 8,
7821 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7822 9, 9, 9, 9, 9, 9,
7823 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7824 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7825 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7826 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7827
7828
7829// This function works for dates from 1970 to 2099.
7830static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007831 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007832#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007833 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007834#endif
7835
7836 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7837 date %= kDaysIn4Years;
7838
7839 month = kMonthInYear[date];
7840 day = kDayInYear[date];
7841
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007842 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007843}
7844
7845
7846static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007847 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007848#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007849 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007850#endif
7851
7852 date += kDaysOffset;
7853 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7854 date %= kDaysIn400Years;
7855
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007856 ASSERT(MakeDay(year, 0) + date == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007857
7858 date--;
7859 int yd1 = date / kDaysIn100Years;
7860 date %= kDaysIn100Years;
7861 year += 100 * yd1;
7862
7863 date++;
7864 int yd2 = date / kDaysIn4Years;
7865 date %= kDaysIn4Years;
7866 year += 4 * yd2;
7867
7868 date--;
7869 int yd3 = date / 365;
7870 date %= 365;
7871 year += yd3;
7872
7873 bool is_leap = (!yd1 || yd2) && !yd3;
7874
7875 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007876 ASSERT(is_leap || (date >= 0));
7877 ASSERT((date < 365) || (is_leap && (date < 366)));
7878 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007879 ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
7880 ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007881
7882 if (is_leap) {
7883 day = kDayInYear[2*365 + 1 + date];
7884 month = kMonthInYear[2*365 + 1 + date];
7885 } else {
7886 day = kDayInYear[date];
7887 month = kMonthInYear[date];
7888 }
7889
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007890 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007891}
7892
7893
7894static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007895 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007896 if (date >= 0 && date < 32 * kDaysIn4Years) {
7897 DateYMDFromTimeAfter1970(date, year, month, day);
7898 } else {
7899 DateYMDFromTimeSlow(date, year, month, day);
7900 }
7901}
7902
7903
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007904RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007905 NoHandleAllocation ha;
7906 ASSERT(args.length() == 2);
7907
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007908 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007909 CONVERT_CHECKED(JSArray, res_array, args[1]);
7910
7911 int year, month, day;
7912 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7913
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007914 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7915 RUNTIME_ASSERT(elms_base->length() == 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007916 RUNTIME_ASSERT(res_array->HasFastTypeElements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007917
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007918 MaybeObject* maybe = res_array->EnsureWritableFastElements();
7919 if (maybe->IsFailure()) return maybe;
7920 FixedArray* elms = FixedArray::cast(res_array->elements());
7921 elms->set(0, Smi::FromInt(year));
7922 elms->set(1, Smi::FromInt(month));
7923 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007924
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007925 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007926}
7927
7928
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007929RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007930 HandleScope scope(isolate);
7931 ASSERT(args.length() == 3);
7932
7933 Handle<JSFunction> callee = args.at<JSFunction>(0);
7934 Object** parameters = reinterpret_cast<Object**>(args[1]);
7935 const int argument_count = Smi::cast(args[2])->value();
7936
7937 Handle<JSObject> result =
7938 isolate->factory()->NewArgumentsObject(callee, argument_count);
7939 // Allocate the elements if needed.
7940 int parameter_count = callee->shared()->formal_parameter_count();
7941 if (argument_count > 0) {
7942 if (parameter_count > 0) {
7943 int mapped_count = Min(argument_count, parameter_count);
7944 Handle<FixedArray> parameter_map =
7945 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7946 parameter_map->set_map(
7947 isolate->heap()->non_strict_arguments_elements_map());
7948
7949 Handle<Map> old_map(result->map());
7950 Handle<Map> new_map =
7951 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007952 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007953
7954 result->set_map(*new_map);
7955 result->set_elements(*parameter_map);
7956
7957 // Store the context and the arguments array at the beginning of the
7958 // parameter map.
7959 Handle<Context> context(isolate->context());
7960 Handle<FixedArray> arguments =
7961 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7962 parameter_map->set(0, *context);
7963 parameter_map->set(1, *arguments);
7964
7965 // Loop over the actual parameters backwards.
7966 int index = argument_count - 1;
7967 while (index >= mapped_count) {
7968 // These go directly in the arguments array and have no
7969 // corresponding slot in the parameter map.
7970 arguments->set(index, *(parameters - index - 1));
7971 --index;
7972 }
7973
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007974 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007975 while (index >= 0) {
7976 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007977 Handle<String> name(scope_info->ParameterName(index));
7978 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007979 bool duplicate = false;
7980 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007981 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007982 duplicate = true;
7983 break;
7984 }
7985 }
7986
7987 if (duplicate) {
7988 // This goes directly in the arguments array with a hole in the
7989 // parameter map.
7990 arguments->set(index, *(parameters - index - 1));
7991 parameter_map->set_the_hole(index + 2);
7992 } else {
7993 // The context index goes in the parameter map with a hole in the
7994 // arguments array.
7995 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007996 for (int j = 0; j < context_local_count; ++j) {
7997 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007998 context_index = j;
7999 break;
8000 }
8001 }
8002 ASSERT(context_index >= 0);
8003 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008004 parameter_map->set(index + 2, Smi::FromInt(
8005 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00008006 }
8007
8008 --index;
8009 }
8010 } else {
8011 // If there is no aliasing, the arguments object elements are not
8012 // special in any way.
8013 Handle<FixedArray> elements =
8014 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
8015 result->set_elements(*elements);
8016 for (int i = 0; i < argument_count; ++i) {
8017 elements->set(i, *(parameters - i - 1));
8018 }
8019 }
8020 }
8021 return *result;
8022}
8023
8024
8025RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008026 NoHandleAllocation ha;
8027 ASSERT(args.length() == 3);
8028
8029 JSFunction* callee = JSFunction::cast(args[0]);
8030 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008031 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008032
lrn@chromium.org303ada72010-10-27 09:33:13 +00008033 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008034 { MaybeObject* maybe_result =
8035 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008036 if (!maybe_result->ToObject(&result)) return maybe_result;
8037 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008038 // Allocate the elements if needed.
8039 if (length > 0) {
8040 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008041 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008042 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008043 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8044 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008045
8046 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008047 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008048 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008049 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008050
8051 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008052 for (int i = 0; i < length; i++) {
8053 array->set(i, *--parameters, mode);
8054 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008055 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008056 }
8057 return result;
8058}
8059
8060
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008061RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008062 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008063 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00008064 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008065 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008066 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008067
whesse@chromium.org7b260152011-06-20 15:33:18 +00008068 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008069 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008070 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008071 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008072 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8073 context,
8074 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008075 return *result;
8076}
8077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008078
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008079// Find the arguments of the JavaScript function invocation that called
8080// into C++ code. Collect these in a newly allocated array of handles (possibly
8081// prefixed by a number of empty handles).
8082static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8083 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008084 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008085 // Find frame containing arguments passed to the caller.
8086 JavaScriptFrameIterator it;
8087 JavaScriptFrame* frame = it.frame();
8088 List<JSFunction*> functions(2);
8089 frame->GetFunctions(&functions);
8090 if (functions.length() > 1) {
8091 int inlined_frame_index = functions.length() - 1;
8092 JSFunction* inlined_function = functions[inlined_frame_index];
8093 int args_count = inlined_function->shared()->formal_parameter_count();
8094 ScopedVector<SlotRef> args_slots(args_count);
8095 SlotRef::ComputeSlotMappingForArguments(frame,
8096 inlined_frame_index,
8097 &args_slots);
8098
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008099 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008100 SmartArrayPointer<Handle<Object> > param_data(
8101 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008102 for (int i = 0; i < args_count; i++) {
8103 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008104 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008105 }
8106 return param_data;
8107 } else {
8108 it.AdvanceToArgumentsFrame();
8109 frame = it.frame();
8110 int args_count = frame->ComputeParametersCount();
8111
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008112 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008113 SmartArrayPointer<Handle<Object> > param_data(
8114 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008115 for (int i = 0; i < args_count; i++) {
8116 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008117 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008118 }
8119 return param_data;
8120 }
8121}
8122
8123
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008124RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8125 HandleScope scope(isolate);
8126 ASSERT(args.length() == 4);
8127 CONVERT_ARG_CHECKED(JSFunction, bound_function, 0);
8128 RUNTIME_ASSERT(args[3]->IsNumber());
8129 Handle<Object> bindee = args.at<Object>(1);
8130
8131 // TODO(lrn): Create bound function in C++ code from premade shared info.
8132 bound_function->shared()->set_bound(true);
8133 // Get all arguments of calling function (Function.prototype.bind).
8134 int argc = 0;
8135 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8136 // Don't count the this-arg.
8137 if (argc > 0) {
8138 ASSERT(*arguments[0] == args[2]);
8139 argc--;
8140 } else {
8141 ASSERT(args[2]->IsUndefined());
8142 }
8143 // Initialize array of bindings (function, this, and any existing arguments
8144 // if the function was already bound).
8145 Handle<FixedArray> new_bindings;
8146 int i;
8147 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8148 Handle<FixedArray> old_bindings(
8149 JSFunction::cast(*bindee)->function_bindings());
8150 new_bindings =
8151 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8152 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8153 i = 0;
8154 for (int n = old_bindings->length(); i < n; i++) {
8155 new_bindings->set(i, old_bindings->get(i));
8156 }
8157 } else {
8158 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8159 new_bindings = isolate->factory()->NewFixedArray(array_size);
8160 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8161 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8162 i = 2;
8163 }
8164 // Copy arguments, skipping the first which is "this_arg".
8165 for (int j = 0; j < argc; j++, i++) {
8166 new_bindings->set(i, *arguments[j + 1]);
8167 }
8168 new_bindings->set_map(isolate->heap()->fixed_cow_array_map());
8169 bound_function->set_function_bindings(*new_bindings);
8170
8171 // Update length.
8172 Handle<String> length_symbol = isolate->factory()->length_symbol();
8173 Handle<Object> new_length(args.at<Object>(3));
8174 PropertyAttributes attr =
8175 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8176 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8177 return *bound_function;
8178}
8179
8180
8181RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8182 HandleScope handles(isolate);
8183 ASSERT(args.length() == 1);
8184 CONVERT_ARG_CHECKED(JSObject, callable, 0);
8185 if (callable->IsJSFunction()) {
8186 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8187 if (function->shared()->bound()) {
8188 Handle<FixedArray> bindings(function->function_bindings());
8189 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8190 return *isolate->factory()->NewJSArrayWithElements(bindings);
8191 }
8192 }
8193 return isolate->heap()->undefined_value();
8194}
8195
8196
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008197RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008198 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008199 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008200 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008201 CONVERT_ARG_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008202 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008203
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008204 // The argument is a bound function. Extract its bound arguments
8205 // and callable.
8206 Handle<FixedArray> bound_args =
8207 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8208 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8209 Handle<Object> bound_function(
8210 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8211 ASSERT(!bound_function->IsJSFunction() ||
8212 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008213
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008214 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008215 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008216 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008217 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008218 param_data[i] = Handle<Object>(bound_args->get(
8219 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008220 }
8221
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008222 if (!bound_function->IsJSFunction()) {
8223 bool exception_thrown;
8224 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8225 &exception_thrown);
8226 if (exception_thrown) return Failure::Exception();
8227 }
8228 ASSERT(bound_function->IsJSFunction());
8229
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008230 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008231 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008232 Execution::New(Handle<JSFunction>::cast(bound_function),
8233 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008234 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008235 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008236 }
8237 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008238 return *result;
8239}
8240
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008241
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008242static void TrySettingInlineConstructStub(Isolate* isolate,
8243 Handle<JSFunction> function) {
8244 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008245 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008246 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008247 }
8248 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008249 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008250 Handle<Code> code = compiler.CompileConstructStub(function);
8251 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008252 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008253}
8254
8255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008256RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008257 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008258 ASSERT(args.length() == 1);
8259
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008260 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008261
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008262 // If the constructor isn't a proper function we throw a type error.
8263 if (!constructor->IsJSFunction()) {
8264 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8265 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008266 isolate->factory()->NewTypeError("not_constructor", arguments);
8267 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008268 }
8269
8270 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008271
8272 // If function should not have prototype, construction is not allowed. In this
8273 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008274 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008275 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8276 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008277 isolate->factory()->NewTypeError("not_constructor", arguments);
8278 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008279 }
8280
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008281#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008282 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008283 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008284 if (debug->StepInActive()) {
8285 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008286 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008287#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008288
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008289 if (function->has_initial_map()) {
8290 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008291 // The 'Function' function ignores the receiver object when
8292 // called using 'new' and creates a new JSFunction object that
8293 // is returned. The receiver object is only used for error
8294 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008295 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008296 // allocate JSFunctions since it does not properly initialize
8297 // the shared part of the function. Since the receiver is
8298 // ignored anyway, we use the global object as the receiver
8299 // instead of a new JSFunction object. This way, errors are
8300 // reported the same way whether or not 'Function' is called
8301 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008302 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008303 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008304 }
8305
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008306 // The function should be compiled for the optimization hints to be
8307 // available. We cannot use EnsureCompiled because that forces a
8308 // compilation through the shared function info which makes it
8309 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008310 if (!function->is_compiled()) {
8311 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8312 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008313
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008314 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008315 if (!function->has_initial_map() &&
8316 shared->IsInobjectSlackTrackingInProgress()) {
8317 // The tracking is already in progress for another function. We can only
8318 // track one initial_map at a time, so we force the completion before the
8319 // function is called as a constructor for the first time.
8320 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008321 }
8322
8323 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008324 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8325 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008326 // Delay setting the stub if inobject slack tracking is in progress.
8327 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008328 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008329 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008330
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008331 isolate->counters()->constructed_objects()->Increment();
8332 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008333
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008334 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008335}
8336
8337
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008338RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008339 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008340 ASSERT(args.length() == 1);
8341
8342 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8343 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008344 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008345
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008346 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008347}
8348
8349
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008350RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008351 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008352 ASSERT(args.length() == 1);
8353
8354 Handle<JSFunction> function = args.at<JSFunction>(0);
8355#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008356 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008357 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008358 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008359 PrintF("]\n");
8360 }
8361#endif
8362
lrn@chromium.org34e60782011-09-15 07:25:40 +00008363 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008364 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008365 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008366 return Failure::Exception();
8367 }
8368
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008369 // All done. Return the compiled code.
8370 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008371 return function->code();
8372}
8373
8374
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008375RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008376 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008377 ASSERT(args.length() == 1);
8378 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008379
8380 // If the function is not compiled ignore the lazy
8381 // recompilation. This can happen if the debugger is activated and
8382 // the function is returned to the not compiled state.
8383 if (!function->shared()->is_compiled()) {
8384 function->ReplaceCode(function->shared()->code());
8385 return function->code();
8386 }
8387
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008388 // If the function is not optimizable or debugger is active continue using the
8389 // code from the full compiler.
8390 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008391 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008392 if (FLAG_trace_opt) {
8393 PrintF("[failed to optimize ");
8394 function->PrintName();
8395 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8396 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008397 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008398 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008399 function->ReplaceCode(function->shared()->code());
8400 return function->code();
8401 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008402 if (JSFunction::CompileOptimized(function,
8403 AstNode::kNoNumber,
8404 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008405 return function->code();
8406 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008407 if (FLAG_trace_opt) {
8408 PrintF("[failed to optimize ");
8409 function->PrintName();
8410 PrintF(": optimized compilation failed]\n");
8411 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008412 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008413 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008414}
8415
8416
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008417class ActivationsFinder : public ThreadVisitor {
8418 public:
8419 explicit ActivationsFinder(JSFunction* function)
8420 : function_(function), has_activations_(false) {}
8421
8422 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8423 if (has_activations_) return;
8424
8425 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8426 JavaScriptFrame* frame = it.frame();
8427 if (frame->is_optimized() && frame->function() == function_) {
8428 has_activations_ = true;
8429 return;
8430 }
8431 }
8432 }
8433
8434 bool has_activations() { return has_activations_; }
8435
8436 private:
8437 JSFunction* function_;
8438 bool has_activations_;
8439};
8440
8441
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008442RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008443 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008444 ASSERT(args.length() == 1);
8445 RUNTIME_ASSERT(args[0]->IsSmi());
8446 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008447 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008448 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8449 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008450 int frames = deoptimizer->output_count();
8451
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008452 deoptimizer->MaterializeHeapNumbers();
8453 delete deoptimizer;
8454
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008455 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008456 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008457 for (int i = 0; i < frames - 1; i++) it.Advance();
8458 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008459
8460 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008461 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008462 Handle<Object> arguments;
8463 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008464 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008465 if (arguments.is_null()) {
8466 // FunctionGetArguments can't throw an exception, so cast away the
8467 // doubt with an assert.
8468 arguments = Handle<Object>(
8469 Accessors::FunctionGetArguments(*function,
8470 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008471 ASSERT(*arguments != isolate->heap()->null_value());
8472 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008473 }
8474 frame->SetExpression(i, *arguments);
8475 }
8476 }
8477
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008478 if (type == Deoptimizer::EAGER) {
8479 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008480 }
8481
8482 // Avoid doing too much work when running with --always-opt and keep
8483 // the optimized code around.
8484 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008485 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008486 }
8487
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008488 // Find other optimized activations of the function.
8489 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008490 while (!it.done()) {
8491 JavaScriptFrame* frame = it.frame();
8492 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008493 has_other_activations = true;
8494 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008495 }
8496 it.Advance();
8497 }
8498
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008499 if (!has_other_activations) {
8500 ActivationsFinder activations_finder(*function);
8501 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8502 has_other_activations = activations_finder.has_activations();
8503 }
8504
8505 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008506 if (FLAG_trace_deopt) {
8507 PrintF("[removing optimized code for: ");
8508 function->PrintName();
8509 PrintF("]\n");
8510 }
8511 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008512 } else {
8513 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008514 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008515 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008516}
8517
8518
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008519RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008520 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008521 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008522 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008523}
8524
8525
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008526RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008527 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008528 ASSERT(args.length() == 1);
8529 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008530 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008531
8532 Deoptimizer::DeoptimizeFunction(*function);
8533
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008534 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008535}
8536
8537
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008538RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8539#if defined(USE_SIMULATOR)
8540 return isolate->heap()->true_value();
8541#else
8542 return isolate->heap()->false_value();
8543#endif
8544}
8545
8546
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008547RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8548 HandleScope scope(isolate);
8549 ASSERT(args.length() == 1);
8550 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8551 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8552 function->MarkForLazyRecompilation();
8553 return isolate->heap()->undefined_value();
8554}
8555
8556
lrn@chromium.org1c092762011-05-09 09:42:16 +00008557RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8558 HandleScope scope(isolate);
8559 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008560 // The least significant bit (after untagging) indicates whether the
8561 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008562 if (!V8::UseCrankshaft()) {
8563 return Smi::FromInt(4); // 4 == "never".
8564 }
8565 if (FLAG_always_opt) {
8566 return Smi::FromInt(3); // 3 == "always".
8567 }
8568 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8569 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8570 : Smi::FromInt(2); // 2 == "no".
8571}
8572
8573
8574RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8575 HandleScope scope(isolate);
8576 ASSERT(args.length() == 1);
8577 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8578 return Smi::FromInt(function->shared()->opt_count());
8579}
8580
8581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008582RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008583 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008584 ASSERT(args.length() == 1);
8585 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8586
8587 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008588 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008589
8590 // We have hit a back edge in an unoptimized frame for a function that was
8591 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008592 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008593 // Keep track of whether we've succeeded in optimizing.
8594 bool succeeded = unoptimized->optimizable();
8595 if (succeeded) {
8596 // If we are trying to do OSR when there are already optimized
8597 // activations of the function, it means (a) the function is directly or
8598 // indirectly recursive and (b) an optimized invocation has been
8599 // deoptimized so that we are currently in an unoptimized activation.
8600 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008601 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008602 while (succeeded && !it.done()) {
8603 JavaScriptFrame* frame = it.frame();
8604 succeeded = !frame->is_optimized() || frame->function() != *function;
8605 it.Advance();
8606 }
8607 }
8608
8609 int ast_id = AstNode::kNoNumber;
8610 if (succeeded) {
8611 // The top JS function is this one, the PC is somewhere in the
8612 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008613 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008614 JavaScriptFrame* frame = it.frame();
8615 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008616 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008617 ASSERT(unoptimized->contains(frame->pc()));
8618
8619 // Use linear search of the unoptimized code's stack check table to find
8620 // the AST id matching the PC.
8621 Address start = unoptimized->instruction_start();
8622 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008623 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008624 uint32_t table_length = Memory::uint32_at(table_cursor);
8625 table_cursor += kIntSize;
8626 for (unsigned i = 0; i < table_length; ++i) {
8627 // Table entries are (AST id, pc offset) pairs.
8628 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8629 if (pc_offset == target_pc_offset) {
8630 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8631 break;
8632 }
8633 table_cursor += 2 * kIntSize;
8634 }
8635 ASSERT(ast_id != AstNode::kNoNumber);
8636 if (FLAG_trace_osr) {
8637 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8638 function->PrintName();
8639 PrintF("]\n");
8640 }
8641
8642 // Try to compile the optimized code. A true return value from
8643 // CompileOptimized means that compilation succeeded, not necessarily
8644 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008645 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008646 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008647 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8648 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008649 if (data->OsrPcOffset()->value() >= 0) {
8650 if (FLAG_trace_osr) {
8651 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008652 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008653 }
8654 ASSERT(data->OsrAstId()->value() == ast_id);
8655 } else {
8656 // We may never generate the desired OSR entry if we emit an
8657 // early deoptimize.
8658 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008659 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008660 } else {
8661 succeeded = false;
8662 }
8663 }
8664
8665 // Revert to the original stack checks in the original unoptimized code.
8666 if (FLAG_trace_osr) {
8667 PrintF("[restoring original stack checks in ");
8668 function->PrintName();
8669 PrintF("]\n");
8670 }
8671 StackCheckStub check_stub;
8672 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008673 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008674 Deoptimizer::RevertStackCheckCode(*unoptimized,
8675 *check_code,
8676 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008677
8678 // Allow OSR only at nesting level zero again.
8679 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8680
8681 // If the optimization attempt succeeded, return the AST id tagged as a
8682 // smi. This tells the builtin that we need to translate the unoptimized
8683 // frame to an optimized one.
8684 if (succeeded) {
8685 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8686 return Smi::FromInt(ast_id);
8687 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008688 if (function->IsMarkedForLazyRecompilation()) {
8689 function->ReplaceCode(function->shared()->code());
8690 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008691 return Smi::FromInt(-1);
8692 }
8693}
8694
8695
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008696RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8697 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8698 return isolate->heap()->undefined_value();
8699}
8700
8701
danno@chromium.orgc612e022011-11-10 11:38:15 +00008702RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8703 HandleScope scope(isolate);
8704 ASSERT(args.length() >= 2);
8705 CONVERT_CHECKED(JSReceiver, fun, args[args.length() - 1]);
8706 Object* receiver = args[0];
8707 int argc = args.length() - 2;
8708
8709 // If there are too many arguments, allocate argv via malloc.
8710 const int argv_small_size = 10;
8711 Handle<Object> argv_small_buffer[argv_small_size];
8712 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8713 Handle<Object>* argv = argv_small_buffer;
8714 if (argc > argv_small_size) {
8715 argv = new Handle<Object>[argc];
8716 if (argv == NULL) return isolate->StackOverflow();
8717 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8718 }
8719
8720 for (int i = 0; i < argc; ++i) {
8721 MaybeObject* maybe = args[1 + i];
8722 Object* object;
8723 if (!maybe->To<Object>(&object)) return maybe;
8724 argv[i] = Handle<Object>(object);
8725 }
8726
8727 bool threw;
8728 Handle<JSReceiver> hfun(fun);
8729 Handle<Object> hreceiver(receiver);
8730 Handle<Object> result =
8731 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8732
8733 if (threw) return Failure::Exception();
8734 return *result;
8735}
8736
8737
lrn@chromium.org34e60782011-09-15 07:25:40 +00008738RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8739 HandleScope scope(isolate);
8740 ASSERT(args.length() == 5);
8741 CONVERT_CHECKED(JSReceiver, fun, args[0]);
8742 Object* receiver = args[1];
8743 CONVERT_CHECKED(JSObject, arguments, args[2]);
8744 CONVERT_CHECKED(Smi, shift, args[3]);
8745 CONVERT_CHECKED(Smi, arity, args[4]);
8746
8747 int offset = shift->value();
8748 int argc = arity->value();
8749 ASSERT(offset >= 0);
8750 ASSERT(argc >= 0);
8751
8752 // If there are too many arguments, allocate argv via malloc.
8753 const int argv_small_size = 10;
8754 Handle<Object> argv_small_buffer[argv_small_size];
8755 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8756 Handle<Object>* argv = argv_small_buffer;
8757 if (argc > argv_small_size) {
8758 argv = new Handle<Object>[argc];
8759 if (argv == NULL) return isolate->StackOverflow();
8760 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8761 }
8762
8763 for (int i = 0; i < argc; ++i) {
8764 MaybeObject* maybe = arguments->GetElement(offset + i);
8765 Object* object;
8766 if (!maybe->To<Object>(&object)) return maybe;
8767 argv[i] = Handle<Object>(object);
8768 }
8769
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008770 bool threw;
lrn@chromium.org34e60782011-09-15 07:25:40 +00008771 Handle<JSReceiver> hfun(fun);
8772 Handle<Object> hreceiver(receiver);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008773 Handle<Object> result =
8774 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008775
8776 if (threw) return Failure::Exception();
8777 return *result;
8778}
8779
8780
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008781RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008782 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008783 ASSERT(args.length() == 1);
8784 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8785 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8786}
8787
8788
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008789RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008790 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008791 ASSERT(args.length() == 1);
8792 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8793 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8794}
8795
8796
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008797RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008798 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008799 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008800
kasper.lund7276f142008-07-30 08:49:36 +00008801 CONVERT_CHECKED(JSFunction, function, args[0]);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008802 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008803 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008804 { MaybeObject* maybe_result =
8805 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008806 if (!maybe_result->ToObject(&result)) return maybe_result;
8807 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008808
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008809 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008810
kasper.lund7276f142008-07-30 08:49:36 +00008811 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008812}
8813
lrn@chromium.org303ada72010-10-27 09:33:13 +00008814
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008815RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8816 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008817 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008818 JSObject* extension_object;
8819 if (args[0]->IsJSObject()) {
8820 extension_object = JSObject::cast(args[0]);
8821 } else {
8822 // Convert the object to a proper JavaScript object.
8823 MaybeObject* maybe_js_object = args[0]->ToObject();
8824 if (!maybe_js_object->To(&extension_object)) {
8825 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8826 HandleScope scope(isolate);
8827 Handle<Object> handle = args.at<Object>(0);
8828 Handle<Object> result =
8829 isolate->factory()->NewTypeError("with_expression",
8830 HandleVector(&handle, 1));
8831 return isolate->Throw(*result);
8832 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008833 return maybe_js_object;
8834 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008835 }
8836 }
8837
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008838 JSFunction* function;
8839 if (args[1]->IsSmi()) {
8840 // A smi sentinel indicates a context nested inside global code rather
8841 // than some function. There is a canonical empty function that can be
8842 // gotten from the global context.
8843 function = isolate->context()->global_context()->closure();
8844 } else {
8845 function = JSFunction::cast(args[1]);
8846 }
8847
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008848 Context* context;
8849 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008850 isolate->heap()->AllocateWithContext(function,
8851 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008852 extension_object);
8853 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008854 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008855 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008856}
8857
8858
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008859RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008860 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008861 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008862 String* name = String::cast(args[0]);
8863 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008864 JSFunction* function;
8865 if (args[2]->IsSmi()) {
8866 // A smi sentinel indicates a context nested inside global code rather
8867 // than some function. There is a canonical empty function that can be
8868 // gotten from the global context.
8869 function = isolate->context()->global_context()->closure();
8870 } else {
8871 function = JSFunction::cast(args[2]);
8872 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008873 Context* context;
8874 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008875 isolate->heap()->AllocateCatchContext(function,
8876 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008877 name,
8878 thrown_object);
8879 if (!maybe_context->To(&context)) return maybe_context;
8880 isolate->set_context(context);
8881 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008882}
8883
8884
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008885RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8886 NoHandleAllocation ha;
8887 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008888 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008889 JSFunction* function;
8890 if (args[1]->IsSmi()) {
8891 // A smi sentinel indicates a context nested inside global code rather
8892 // than some function. There is a canonical empty function that can be
8893 // gotten from the global context.
8894 function = isolate->context()->global_context()->closure();
8895 } else {
8896 function = JSFunction::cast(args[1]);
8897 }
8898 Context* context;
8899 MaybeObject* maybe_context =
8900 isolate->heap()->AllocateBlockContext(function,
8901 isolate->context(),
8902 scope_info);
8903 if (!maybe_context->To(&context)) return maybe_context;
8904 isolate->set_context(context);
8905 return context;
8906}
8907
8908
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008909RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008910 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008911 ASSERT(args.length() == 2);
8912
8913 CONVERT_ARG_CHECKED(Context, context, 0);
8914 CONVERT_ARG_CHECKED(String, name, 1);
8915
8916 int index;
8917 PropertyAttributes attributes;
8918 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008919 BindingFlags binding_flags;
8920 Handle<Object> holder = context->Lookup(name,
8921 flags,
8922 &index,
8923 &attributes,
8924 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008925
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008926 // If the slot was not found the result is true.
8927 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008928 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008929 }
8930
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008931 // If the slot was found in a context, it should be DONT_DELETE.
8932 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008933 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008934 }
8935
8936 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008937 // the global object, or the subject of a with. Try to delete it
8938 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008939 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008940 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008941}
8942
8943
ager@chromium.orga1645e22009-09-09 19:27:10 +00008944// A mechanism to return a pair of Object pointers in registers (if possible).
8945// How this is achieved is calling convention-dependent.
8946// All currently supported x86 compiles uses calling conventions that are cdecl
8947// variants where a 64-bit value is returned in two 32-bit registers
8948// (edx:eax on ia32, r1:r0 on ARM).
8949// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8950// In Win64 calling convention, a struct of two pointers is returned in memory,
8951// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008952#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008953struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008954 MaybeObject* x;
8955 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008956};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008957
lrn@chromium.org303ada72010-10-27 09:33:13 +00008958static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008959 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008960 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8961 // In Win64 they are assigned to a hidden first argument.
8962 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008963}
8964#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008965typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008966static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008967 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008968 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008969}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008970#endif
8971
8972
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008973static inline MaybeObject* Unhole(Heap* heap,
8974 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008975 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008976 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8977 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008978 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008979}
8980
8981
danno@chromium.org40cb8782011-05-25 07:58:50 +00008982static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8983 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008984 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008985 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008986 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008987 JSFunction* context_extension_function =
8988 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008989 // If the holder isn't a context extension object, we just return it
8990 // as the receiver. This allows arguments objects to be used as
8991 // receivers, but only if they are put in the context scope chain
8992 // explicitly via a with-statement.
8993 Object* constructor = holder->map()->constructor();
8994 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008995 // Fall back to using the global object as the implicit receiver if
8996 // the property turns out to be a local variable allocated in a
8997 // context extension object - introduced via eval. Implicit global
8998 // receivers are indicated with the hole value.
8999 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009000}
9001
9002
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009003static ObjectPair LoadContextSlotHelper(Arguments args,
9004 Isolate* isolate,
9005 bool throw_error) {
9006 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00009007 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009008
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009009 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009010 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009011 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009012 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009013 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009014
9015 int index;
9016 PropertyAttributes attributes;
9017 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009018 BindingFlags binding_flags;
9019 Handle<Object> holder = context->Lookup(name,
9020 flags,
9021 &index,
9022 &attributes,
9023 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009024
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009025 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009026 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009027 ASSERT(holder->IsContext());
9028 // If the "property" we were looking for is a local variable, the
9029 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00009030 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009031 // Use the hole as the receiver to signal that the receiver is implicit
9032 // and that the global receiver should be used (as distinguished from an
9033 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00009034 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009035 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009036 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009037 switch (binding_flags) {
9038 case MUTABLE_CHECK_INITIALIZED:
9039 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9040 if (value->IsTheHole()) {
9041 Handle<Object> reference_error =
9042 isolate->factory()->NewReferenceError("not_defined",
9043 HandleVector(&name, 1));
9044 return MakePair(isolate->Throw(*reference_error), NULL);
9045 }
9046 // FALLTHROUGH
9047 case MUTABLE_IS_INITIALIZED:
9048 case IMMUTABLE_IS_INITIALIZED:
9049 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9050 ASSERT(!value->IsTheHole());
9051 return MakePair(value, *receiver);
9052 case IMMUTABLE_CHECK_INITIALIZED:
9053 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9054 case MISSING_BINDING:
9055 UNREACHABLE();
9056 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009057 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009058 }
9059
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009060 // Otherwise, if the slot was found the holder is a context extension
9061 // object, subject of a with, or a global object. We read the named
9062 // property from it.
9063 if (!holder.is_null()) {
9064 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9065 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009066 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009067 Handle<Object> receiver_handle(object->IsGlobalObject()
9068 ? GlobalObject::cast(*object)->global_receiver()
9069 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009070
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009071 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009072 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009073 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009074 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009075 }
9076
9077 if (throw_error) {
9078 // The property doesn't exist - throw exception.
9079 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009080 isolate->factory()->NewReferenceError("not_defined",
9081 HandleVector(&name, 1));
9082 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009083 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009084 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009085 return MakePair(isolate->heap()->undefined_value(),
9086 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009087 }
9088}
9089
9090
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009091RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009092 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009093}
9094
9095
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009096RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009097 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009098}
9099
9100
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009101RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009102 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009103 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009104
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009105 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009106 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009107 CONVERT_ARG_CHECKED(String, name, 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009108 CONVERT_STRICT_MODE_ARG(strict_mode, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009109
9110 int index;
9111 PropertyAttributes attributes;
9112 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009113 BindingFlags binding_flags;
9114 Handle<Object> holder = context->Lookup(name,
9115 flags,
9116 &index,
9117 &attributes,
9118 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009119
9120 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009121 // The property was found in a context slot.
9122 Handle<Context> context = Handle<Context>::cast(holder);
9123 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9124 context->get(index)->IsTheHole()) {
9125 Handle<Object> error =
9126 isolate->factory()->NewReferenceError("not_defined",
9127 HandleVector(&name, 1));
9128 return isolate->Throw(*error);
9129 }
9130 // Ignore if read_only variable.
9131 if ((attributes & READ_ONLY) == 0) {
9132 // Context is a fixed array and set cannot fail.
9133 context->set(index, *value);
9134 } else if (strict_mode == kStrictMode) {
9135 // Setting read only property in strict mode.
9136 Handle<Object> error =
9137 isolate->factory()->NewTypeError("strict_cannot_assign",
9138 HandleVector(&name, 1));
9139 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009140 }
9141 return *value;
9142 }
9143
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009144 // Slow case: The property is not in a context slot. It is either in a
9145 // context extension object, a property of the subject of a with, or a
9146 // property of the global object.
9147 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009148
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009149 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009150 // The property exists on the holder.
9151 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009152 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009153 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009154 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009155
9156 if (strict_mode == kStrictMode) {
9157 // Throw in strict mode (assignment to undefined variable).
9158 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009159 isolate->factory()->NewReferenceError(
9160 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009161 return isolate->Throw(*error);
9162 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009163 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009164 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009165 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009166 }
9167
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009168 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009169 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009170 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009171 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009172 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009173 SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009174 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009175 // Setting read only property in strict mode.
9176 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009177 isolate->factory()->NewTypeError(
9178 "strict_cannot_assign", HandleVector(&name, 1));
9179 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009180 }
9181 return *value;
9182}
9183
9184
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009185RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009186 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009187 ASSERT(args.length() == 1);
9188
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009189 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009190}
9191
9192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009193RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009194 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009195 ASSERT(args.length() == 1);
9196
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009197 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009198}
9199
9200
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009201RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009202 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009203 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009204}
9205
9206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009207RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009208 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009209 ASSERT(args.length() == 1);
9210
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009211 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009212 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009213 isolate->factory()->NewReferenceError("not_defined",
9214 HandleVector(&name, 1));
9215 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009216}
9217
9218
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009219RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009220 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009221
9222 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009223 if (isolate->stack_guard()->IsStackOverflow()) {
9224 NoHandleAllocation na;
9225 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009226 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009227
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009228 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009229}
9230
9231
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009232static int StackSize() {
9233 int n = 0;
9234 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9235 return n;
9236}
9237
9238
9239static void PrintTransition(Object* result) {
9240 // indentation
9241 { const int nmax = 80;
9242 int n = StackSize();
9243 if (n <= nmax)
9244 PrintF("%4d:%*s", n, n, "");
9245 else
9246 PrintF("%4d:%*s", n, nmax, "...");
9247 }
9248
9249 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009250 JavaScriptFrame::PrintTop(stdout, true, false);
9251 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009252 } else {
9253 // function result
9254 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009255 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009256 PrintF("\n");
9257 }
9258}
9259
9260
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009261RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceElementsKindTransition) {
9262 ASSERT(args.length() == 5);
9263 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9264 CONVERT_SMI_ARG_CHECKED(from_kind, 1);
9265 CONVERT_ARG_CHECKED(FixedArrayBase, from_elements, 2);
9266 CONVERT_SMI_ARG_CHECKED(to_kind, 3);
9267 CONVERT_ARG_CHECKED(FixedArrayBase, to_elements, 4);
9268 NoHandleAllocation ha;
9269 PrintF("*");
9270 obj->PrintElementsTransition(stdout,
9271 static_cast<ElementsKind>(from_kind), *from_elements,
9272 static_cast<ElementsKind>(to_kind), *to_elements);
9273 return isolate->heap()->undefined_value();
9274}
9275
9276
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009277RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009278 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009279 NoHandleAllocation ha;
9280 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009281 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009282}
9283
9284
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009285RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009286 NoHandleAllocation ha;
9287 PrintTransition(args[0]);
9288 return args[0]; // return TOS
9289}
9290
9291
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009292RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009293 NoHandleAllocation ha;
9294 ASSERT(args.length() == 1);
9295
9296#ifdef DEBUG
9297 if (args[0]->IsString()) {
9298 // If we have a string, assume it's a code "marker"
9299 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009300 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009301 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009302 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9303 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009304 } else {
9305 PrintF("DebugPrint: ");
9306 }
9307 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009308 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009309 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009310 HeapObject::cast(args[0])->map()->Print();
9311 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009312#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009313 // ShortPrint is available in release mode. Print is not.
9314 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009315#endif
9316 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009317 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009318
9319 return args[0]; // return TOS
9320}
9321
9322
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009323RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009324 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009325 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009326 isolate->PrintStack();
9327 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009328}
9329
9330
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009331RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009332 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009333 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009334
9335 // According to ECMA-262, section 15.9.1, page 117, the precision of
9336 // the number in a Date object representing a particular instant in
9337 // time is milliseconds. Therefore, we floor the result of getting
9338 // the OS time.
9339 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009340 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009341}
9342
9343
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009344RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009345 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009346 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009347
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009348 CONVERT_ARG_CHECKED(String, str, 0);
9349 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009350
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009351 CONVERT_ARG_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009352
9353 MaybeObject* maybe_result_array =
9354 output->EnsureCanContainNonSmiElements();
9355 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009356 RUNTIME_ASSERT(output->HasFastElements());
9357
9358 AssertNoAllocation no_allocation;
9359
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009360 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009361 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9362 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009363 String::FlatContent str_content = str->GetFlatContent();
9364 if (str_content.IsAscii()) {
9365 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009366 output_array,
9367 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009368 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009369 ASSERT(str_content.IsTwoByte());
9370 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009371 output_array,
9372 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009373 }
9374
9375 if (result) {
9376 return *output;
9377 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009378 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009379 }
9380}
9381
9382
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009383RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009384 NoHandleAllocation ha;
9385 ASSERT(args.length() == 1);
9386
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009387 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009388 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009389 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009390}
9391
9392
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009393RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009394 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009395 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009396
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009397 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009398}
9399
9400
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009401RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009402 NoHandleAllocation ha;
9403 ASSERT(args.length() == 1);
9404
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009405 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009406 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009407}
9408
9409
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009410RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009411 ASSERT(args.length() == 1);
9412 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009413 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009414 return JSGlobalObject::cast(global)->global_receiver();
9415}
9416
9417
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009418RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009419 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009420 ASSERT_EQ(1, args.length());
9421 CONVERT_ARG_CHECKED(String, source, 0);
9422
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009423 source = Handle<String>(source->TryFlattenGetString());
9424 // Optimized fast case where we only have ascii characters.
9425 Handle<Object> result;
9426 if (source->IsSeqAsciiString()) {
9427 result = JsonParser<true>::Parse(source);
9428 } else {
9429 result = JsonParser<false>::Parse(source);
9430 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009431 if (result.is_null()) {
9432 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009433 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009434 return Failure::Exception();
9435 }
9436 return *result;
9437}
9438
9439
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009440bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9441 Handle<Context> context) {
9442 if (context->allow_code_gen_from_strings()->IsFalse()) {
9443 // Check with callback if set.
9444 AllowCodeGenerationFromStringsCallback callback =
9445 isolate->allow_code_gen_callback();
9446 if (callback == NULL) {
9447 // No callback set and code generation disallowed.
9448 return false;
9449 } else {
9450 // Callback set. Let it decide if code generation is allowed.
9451 VMState state(isolate, EXTERNAL);
9452 return callback(v8::Utils::ToLocal(context));
9453 }
9454 }
9455 return true;
9456}
9457
9458
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009459RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009460 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009461 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009462 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009463
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009464 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009465 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009466
9467 // Check if global context allows code generation from
9468 // strings. Throw an exception if it doesn't.
9469 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
9470 return isolate->Throw(*isolate->factory()->NewError(
9471 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9472 }
9473
9474 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009475 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
9476 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009477 true,
9478 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009479 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009480 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009481 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9482 context,
9483 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009484 return *fun;
9485}
9486
9487
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009488static ObjectPair CompileGlobalEval(Isolate* isolate,
9489 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009490 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009491 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009492 Handle<Context> context = Handle<Context>(isolate->context());
9493 Handle<Context> global_context = Handle<Context>(context->global_context());
9494
9495 // Check if global context allows code generation from
9496 // strings. Throw an exception if it doesn't.
9497 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
9498 isolate->Throw(*isolate->factory()->NewError(
9499 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9500 return MakePair(Failure::Exception(), NULL);
9501 }
9502
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009503 // Deal with a normal eval call with a string argument. Compile it
9504 // and return the compiled function bound in the local context.
9505 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9506 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009507 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009508 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009509 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009510 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009511 Handle<JSFunction> compiled =
9512 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009513 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009514 return MakePair(*compiled, *receiver);
9515}
9516
9517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009518RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009519 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009520
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009521 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009522 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009523
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009524 // If "eval" didn't refer to the original GlobalEval, it's not a
9525 // direct call to eval.
9526 // (And even if it is, but the first argument isn't a string, just let
9527 // execution default to an indirect call to eval, which will also return
9528 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009529 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009530 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009531 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009532 }
9533
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009534 CONVERT_STRICT_MODE_ARG(strict_mode, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009535 return CompileGlobalEval(isolate,
9536 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009537 args.at<Object>(2),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009538 strict_mode);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009539}
9540
9541
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009542RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009543 // This utility adjusts the property attributes for newly created Function
9544 // object ("new Function(...)") by changing the map.
9545 // All it does is changing the prototype property to enumerable
9546 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009547 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009548 ASSERT(args.length() == 1);
9549 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009550
9551 Handle<Map> map = func->shared()->strict_mode()
9552 ? isolate->strict_mode_function_instance_map()
9553 : isolate->function_instance_map();
9554
9555 ASSERT(func->map()->instance_type() == map->instance_type());
9556 ASSERT(func->map()->instance_size() == map->instance_size());
9557 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009558 return *func;
9559}
9560
9561
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009562RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009563 // Allocate a block of memory in NewSpace (filled with a filler).
9564 // Use as fallback for allocation in generated code when NewSpace
9565 // is full.
9566 ASSERT(args.length() == 1);
9567 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9568 int size = size_smi->value();
9569 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9570 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009571 Heap* heap = isolate->heap();
9572 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009573 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009574 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009575 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009576 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009577 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009578 }
9579 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009580 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009581}
9582
9583
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009584// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009585// array. Returns true if the element was pushed on the stack and
9586// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009587RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009588 ASSERT(args.length() == 2);
9589 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009590 CONVERT_CHECKED(JSObject, element, args[1]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009591 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009592 int length = Smi::cast(array->length())->value();
9593 FixedArray* elements = FixedArray::cast(array->elements());
9594 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009595 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009596 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009597 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009598 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009599 { MaybeObject* maybe_obj =
9600 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009601 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9602 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009603 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009604}
9605
9606
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009607/**
9608 * A simple visitor visits every element of Array's.
9609 * The backend storage can be a fixed array for fast elements case,
9610 * or a dictionary for sparse array. Since Dictionary is a subtype
9611 * of FixedArray, the class can be used by both fast and slow cases.
9612 * The second parameter of the constructor, fast_elements, specifies
9613 * whether the storage is a FixedArray or Dictionary.
9614 *
9615 * An index limit is used to deal with the situation that a result array
9616 * length overflows 32-bit non-negative integer.
9617 */
9618class ArrayConcatVisitor {
9619 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009620 ArrayConcatVisitor(Isolate* isolate,
9621 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009622 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009623 isolate_(isolate),
9624 storage_(Handle<FixedArray>::cast(
9625 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009626 index_offset_(0u),
9627 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009628
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009629 ~ArrayConcatVisitor() {
9630 clear_storage();
9631 }
9632
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009633 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009634 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009635 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009636
9637 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009638 if (index < static_cast<uint32_t>(storage_->length())) {
9639 storage_->set(index, *elm);
9640 return;
9641 }
9642 // Our initial estimate of length was foiled, possibly by
9643 // getters on the arrays increasing the length of later arrays
9644 // during iteration.
9645 // This shouldn't happen in anything but pathological cases.
9646 SetDictionaryMode(index);
9647 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009648 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009649 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009650 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009651 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009652 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009653 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009654 // Dictionary needed to grow.
9655 clear_storage();
9656 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009657 }
9658}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009659
9660 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009661 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9662 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009663 } else {
9664 index_offset_ += delta;
9665 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009666 }
9667
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009668 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009669 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009670 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009671 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009672 Handle<Map> map;
9673 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009674 map = isolate_->factory()->GetElementsTransitionMap(array,
9675 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009676 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009677 map = isolate_->factory()->GetElementsTransitionMap(array,
9678 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009679 }
9680 array->set_map(*map);
9681 array->set_length(*length);
9682 array->set_elements(*storage_);
9683 return array;
9684 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009685
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009686 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009687 // Convert storage to dictionary mode.
9688 void SetDictionaryMode(uint32_t index) {
9689 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009690 Handle<FixedArray> current_storage(*storage_);
9691 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009692 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009693 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9694 for (uint32_t i = 0; i < current_length; i++) {
9695 HandleScope loop_scope;
9696 Handle<Object> element(current_storage->get(i));
9697 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009698 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009699 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009700 if (!new_storage.is_identical_to(slow_storage)) {
9701 slow_storage = loop_scope.CloseAndEscape(new_storage);
9702 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009703 }
9704 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009705 clear_storage();
9706 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009707 fast_elements_ = false;
9708 }
9709
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009710 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009711 isolate_->global_handles()->Destroy(
9712 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009713 }
9714
9715 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009716 storage_ = Handle<FixedArray>::cast(
9717 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009718 }
9719
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009720 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009721 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009722 // Index after last seen index. Always less than or equal to
9723 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009724 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009725 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009726};
9727
9728
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009729static uint32_t EstimateElementCount(Handle<JSArray> array) {
9730 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9731 int element_count = 0;
9732 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009733 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009734 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009735 // Fast elements can't have lengths that are not representable by
9736 // a 32-bit signed integer.
9737 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9738 int fast_length = static_cast<int>(length);
9739 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9740 for (int i = 0; i < fast_length; i++) {
9741 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009742 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009743 break;
9744 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009745 case FAST_DOUBLE_ELEMENTS:
9746 // TODO(1810): Decide if it's worthwhile to implement this.
9747 UNREACHABLE();
9748 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009749 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009750 Handle<NumberDictionary> dictionary(
9751 NumberDictionary::cast(array->elements()));
9752 int capacity = dictionary->Capacity();
9753 for (int i = 0; i < capacity; i++) {
9754 Handle<Object> key(dictionary->KeyAt(i));
9755 if (dictionary->IsKey(*key)) {
9756 element_count++;
9757 }
9758 }
9759 break;
9760 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009761 case NON_STRICT_ARGUMENTS_ELEMENTS:
9762 case EXTERNAL_BYTE_ELEMENTS:
9763 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9764 case EXTERNAL_SHORT_ELEMENTS:
9765 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9766 case EXTERNAL_INT_ELEMENTS:
9767 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9768 case EXTERNAL_FLOAT_ELEMENTS:
9769 case EXTERNAL_DOUBLE_ELEMENTS:
9770 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009771 // External arrays are always dense.
9772 return length;
9773 }
9774 // As an estimate, we assume that the prototype doesn't contain any
9775 // inherited elements.
9776 return element_count;
9777}
9778
9779
9780
9781template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009782static void IterateExternalArrayElements(Isolate* isolate,
9783 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009784 bool elements_are_ints,
9785 bool elements_are_guaranteed_smis,
9786 ArrayConcatVisitor* visitor) {
9787 Handle<ExternalArrayClass> array(
9788 ExternalArrayClass::cast(receiver->elements()));
9789 uint32_t len = static_cast<uint32_t>(array->length());
9790
9791 ASSERT(visitor != NULL);
9792 if (elements_are_ints) {
9793 if (elements_are_guaranteed_smis) {
9794 for (uint32_t j = 0; j < len; j++) {
9795 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009796 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009797 visitor->visit(j, e);
9798 }
9799 } else {
9800 for (uint32_t j = 0; j < len; j++) {
9801 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009802 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009803 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9804 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9805 visitor->visit(j, e);
9806 } else {
9807 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009808 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009809 visitor->visit(j, e);
9810 }
9811 }
9812 }
9813 } else {
9814 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009815 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009816 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009817 visitor->visit(j, e);
9818 }
9819 }
9820}
9821
9822
9823// Used for sorting indices in a List<uint32_t>.
9824static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9825 uint32_t a = *ap;
9826 uint32_t b = *bp;
9827 return (a == b) ? 0 : (a < b) ? -1 : 1;
9828}
9829
9830
9831static void CollectElementIndices(Handle<JSObject> object,
9832 uint32_t range,
9833 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009834 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009835 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009836 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009837 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009838 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9839 uint32_t length = static_cast<uint32_t>(elements->length());
9840 if (range < length) length = range;
9841 for (uint32_t i = 0; i < length; i++) {
9842 if (!elements->get(i)->IsTheHole()) {
9843 indices->Add(i);
9844 }
9845 }
9846 break;
9847 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009848 case FAST_DOUBLE_ELEMENTS: {
9849 // TODO(1810): Decide if it's worthwhile to implement this.
9850 UNREACHABLE();
9851 break;
9852 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009853 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009854 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009855 uint32_t capacity = dict->Capacity();
9856 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009857 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009858 Handle<Object> k(dict->KeyAt(j));
9859 if (dict->IsKey(*k)) {
9860 ASSERT(k->IsNumber());
9861 uint32_t index = static_cast<uint32_t>(k->Number());
9862 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009863 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009864 }
9865 }
9866 }
9867 break;
9868 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009869 default: {
9870 int dense_elements_length;
9871 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009872 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009873 dense_elements_length =
9874 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009875 break;
9876 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009877 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009878 dense_elements_length =
9879 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009880 break;
9881 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009882 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009883 dense_elements_length =
9884 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009885 break;
9886 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009887 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009888 dense_elements_length =
9889 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009890 break;
9891 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009892 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009893 dense_elements_length =
9894 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009895 break;
9896 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009897 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009898 dense_elements_length =
9899 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009900 break;
9901 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009902 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009903 dense_elements_length =
9904 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009905 break;
9906 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009907 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009908 dense_elements_length =
9909 ExternalFloatArray::cast(object->elements())->length();
9910 break;
9911 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009912 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009913 dense_elements_length =
9914 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009915 break;
9916 }
9917 default:
9918 UNREACHABLE();
9919 dense_elements_length = 0;
9920 break;
9921 }
9922 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9923 if (range <= length) {
9924 length = range;
9925 // We will add all indices, so we might as well clear it first
9926 // and avoid duplicates.
9927 indices->Clear();
9928 }
9929 for (uint32_t i = 0; i < length; i++) {
9930 indices->Add(i);
9931 }
9932 if (length == range) return; // All indices accounted for already.
9933 break;
9934 }
9935 }
9936
9937 Handle<Object> prototype(object->GetPrototype());
9938 if (prototype->IsJSObject()) {
9939 // The prototype will usually have no inherited element indices,
9940 // but we have to check.
9941 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9942 }
9943}
9944
9945
9946/**
9947 * A helper function that visits elements of a JSArray in numerical
9948 * order.
9949 *
9950 * The visitor argument called for each existing element in the array
9951 * with the element index and the element's value.
9952 * Afterwards it increments the base-index of the visitor by the array
9953 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009954 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009955 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009956static bool IterateElements(Isolate* isolate,
9957 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009958 ArrayConcatVisitor* visitor) {
9959 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9960 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009961 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009962 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009963 // Run through the elements FixedArray and use HasElement and GetElement
9964 // to check the prototype for missing elements.
9965 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9966 int fast_length = static_cast<int>(length);
9967 ASSERT(fast_length <= elements->length());
9968 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009969 HandleScope loop_scope(isolate);
9970 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009971 if (!element_value->IsTheHole()) {
9972 visitor->visit(j, element_value);
9973 } else if (receiver->HasElement(j)) {
9974 // Call GetElement on receiver, not its prototype, or getters won't
9975 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009976 element_value = Object::GetElement(receiver, j);
9977 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009978 visitor->visit(j, element_value);
9979 }
9980 }
9981 break;
9982 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009983 case FAST_DOUBLE_ELEMENTS: {
9984 // TODO(1810): Decide if it's worthwhile to implement this.
9985 UNREACHABLE();
9986 break;
9987 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009988 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009989 Handle<NumberDictionary> dict(receiver->element_dictionary());
9990 List<uint32_t> indices(dict->Capacity() / 2);
9991 // Collect all indices in the object and the prototypes less
9992 // than length. This might introduce duplicates in the indices list.
9993 CollectElementIndices(receiver, length, &indices);
9994 indices.Sort(&compareUInt32);
9995 int j = 0;
9996 int n = indices.length();
9997 while (j < n) {
9998 HandleScope loop_scope;
9999 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010000 Handle<Object> element = Object::GetElement(receiver, index);
10001 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010002 visitor->visit(index, element);
10003 // Skip to next different index (i.e., omit duplicates).
10004 do {
10005 j++;
10006 } while (j < n && indices[j] == index);
10007 }
10008 break;
10009 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010010 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010011 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
10012 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010013 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010014 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010015 visitor->visit(j, e);
10016 }
10017 break;
10018 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010019 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010020 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010021 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010022 break;
10023 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010024 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010025 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010026 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010027 break;
10028 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010029 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010030 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010031 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010032 break;
10033 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010034 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010035 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010036 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010037 break;
10038 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010039 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010040 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010041 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010042 break;
10043 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010044 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010045 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010046 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010047 break;
10048 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010049 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010050 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010051 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010052 break;
10053 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010054 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010055 IterateExternalArrayElements<ExternalDoubleArray, double>(
10056 isolate, receiver, false, false, visitor);
10057 break;
10058 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010059 default:
10060 UNREACHABLE();
10061 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010062 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010063 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010064 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010065}
10066
10067
10068/**
10069 * Array::concat implementation.
10070 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010071 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010072 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010073 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010074RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010075 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010076 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010077
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010078 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
10079 int argument_count = static_cast<int>(arguments->length()->Number());
10080 RUNTIME_ASSERT(arguments->HasFastElements());
10081 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010082
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010083 // Pass 1: estimate the length and number of elements of the result.
10084 // The actual length can be larger if any of the arguments have getters
10085 // that mutate other arguments (but will otherwise be precise).
10086 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010087
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010088 uint32_t estimate_result_length = 0;
10089 uint32_t estimate_nof_elements = 0;
10090 {
10091 for (int i = 0; i < argument_count; i++) {
10092 HandleScope loop_scope;
10093 Handle<Object> obj(elements->get(i));
10094 uint32_t length_estimate;
10095 uint32_t element_estimate;
10096 if (obj->IsJSArray()) {
10097 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010098 // TODO(1810): Find out if it's worthwhile to properly support
10099 // arbitrary ElementsKinds. For now, pessimistically transition to
10100 // FAST_ELEMENTS.
10101 if (array->HasFastDoubleElements()) {
10102 array = Handle<JSArray>::cast(
10103 TransitionElementsKind(array, FAST_ELEMENTS));
10104 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010105 length_estimate =
10106 static_cast<uint32_t>(array->length()->Number());
10107 element_estimate =
10108 EstimateElementCount(array);
10109 } else {
10110 length_estimate = 1;
10111 element_estimate = 1;
10112 }
10113 // Avoid overflows by capping at kMaxElementCount.
10114 if (JSObject::kMaxElementCount - estimate_result_length <
10115 length_estimate) {
10116 estimate_result_length = JSObject::kMaxElementCount;
10117 } else {
10118 estimate_result_length += length_estimate;
10119 }
10120 if (JSObject::kMaxElementCount - estimate_nof_elements <
10121 element_estimate) {
10122 estimate_nof_elements = JSObject::kMaxElementCount;
10123 } else {
10124 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010125 }
10126 }
10127 }
10128
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010129 // If estimated number of elements is more than half of length, a
10130 // fixed array (fast case) is more time and space-efficient than a
10131 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010132 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010133
10134 Handle<FixedArray> storage;
10135 if (fast_case) {
10136 // The backing storage array must have non-existing elements to
10137 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010138 storage = isolate->factory()->NewFixedArrayWithHoles(
10139 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010140 } else {
10141 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10142 uint32_t at_least_space_for = estimate_nof_elements +
10143 (estimate_nof_elements >> 2);
10144 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010145 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010146 }
10147
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010148 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010149
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010150 for (int i = 0; i < argument_count; i++) {
10151 Handle<Object> obj(elements->get(i));
10152 if (obj->IsJSArray()) {
10153 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010154 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010155 return Failure::Exception();
10156 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010157 } else {
10158 visitor.visit(0, obj);
10159 visitor.increase_index_offset(1);
10160 }
10161 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010162
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010163 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010164}
10165
10166
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010167// This will not allocate (flatten the string), but it may run
10168// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010169RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010170 NoHandleAllocation ha;
10171 ASSERT(args.length() == 1);
10172
10173 CONVERT_CHECKED(String, string, args[0]);
10174 StringInputBuffer buffer(string);
10175 while (buffer.has_more()) {
10176 uint16_t character = buffer.GetNext();
10177 PrintF("%c", character);
10178 }
10179 return string;
10180}
10181
ager@chromium.org5ec48922009-05-05 07:25:34 +000010182// Moves all own elements of an object, that are below a limit, to positions
10183// starting at zero. All undefined values are placed after non-undefined values,
10184// and are followed by non-existing element. Does not change the length
10185// property.
10186// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010187RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010188 ASSERT(args.length() == 2);
10189 CONVERT_CHECKED(JSObject, object, args[0]);
10190 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10191 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010192}
10193
10194
10195// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010196RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010197 ASSERT(args.length() == 2);
10198 CONVERT_CHECKED(JSArray, from, args[0]);
10199 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010200 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010201 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010202 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010203 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10204 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010205 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010206 } else if (new_elements->map() ==
10207 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010208 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010209 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010210 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010211 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010212 maybe_new_map = to->GetElementsTransitionMap(elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010213 Object* new_map;
10214 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010215 to->set_map(Map::cast(new_map));
10216 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010217 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010218 Object* obj;
10219 { MaybeObject* maybe_obj = from->ResetElements();
10220 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10221 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010222 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010223 return to;
10224}
10225
10226
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010227// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010228RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010229 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010230 CONVERT_CHECKED(JSObject, object, args[0]);
10231 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010232 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010233 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010234 } else if (object->IsJSArray()) {
10235 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010236 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010237 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010238 }
10239}
10240
10241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010242RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010243 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010244
10245 ASSERT_EQ(3, args.length());
10246
ager@chromium.orgac091b72010-05-05 07:34:42 +000010247 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010248 Handle<Object> key1 = args.at<Object>(1);
10249 Handle<Object> key2 = args.at<Object>(2);
10250
10251 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010252 if (!key1->ToArrayIndex(&index1)
10253 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010254 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010255 }
10256
ager@chromium.orgac091b72010-05-05 07:34:42 +000010257 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010258 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010259 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010260 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010261 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010262
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010263 RETURN_IF_EMPTY_HANDLE(isolate,
10264 SetElement(jsobject, index1, tmp2, kStrictMode));
10265 RETURN_IF_EMPTY_HANDLE(isolate,
10266 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010267
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010268 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010269}
10270
10271
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010272// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010273// might have elements. Can either return keys (positive integers) or
10274// intervals (pair of a negative integer (-start-1) followed by a
10275// positive (length)) or undefined values.
10276// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010277RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010278 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010279 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010280 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010281 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010282 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010283 // Create an array and get all the keys into it, then remove all the
10284 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010285 bool threw = false;
10286 Handle<FixedArray> keys =
10287 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10288 if (threw) return Failure::Exception();
10289
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010290 int keys_length = keys->length();
10291 for (int i = 0; i < keys_length; i++) {
10292 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010293 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010294 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010295 // Zap invalid keys.
10296 keys->set_undefined(i);
10297 }
10298 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010299 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010300 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010301 ASSERT(array->HasFastElements() ||
10302 array->HasFastSmiOnlyElements() ||
10303 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010304 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010305 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010306 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010307 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010308 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010309 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010310 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010311 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010312 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010313 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010314 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010315 }
10316}
10317
10318
10319// DefineAccessor takes an optional final argument which is the
10320// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
10321// to the way accessors are implemented, it is set for both the getter
10322// and setter on the first call to DefineAccessor and ignored on
10323// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010324RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010325 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10326 // Compute attributes.
10327 PropertyAttributes attributes = NONE;
10328 if (args.length() == 5) {
10329 CONVERT_CHECKED(Smi, attrs, args[4]);
10330 int value = attrs->value();
10331 // Only attribute bits should be set.
10332 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10333 attributes = static_cast<PropertyAttributes>(value);
10334 }
10335
10336 CONVERT_CHECKED(JSObject, obj, args[0]);
10337 CONVERT_CHECKED(String, name, args[1]);
10338 CONVERT_CHECKED(Smi, flag, args[2]);
10339 CONVERT_CHECKED(JSFunction, fun, args[3]);
10340 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10341}
10342
10343
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010344RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010345 ASSERT(args.length() == 3);
10346 CONVERT_CHECKED(JSObject, obj, args[0]);
10347 CONVERT_CHECKED(String, name, args[1]);
10348 CONVERT_CHECKED(Smi, flag, args[2]);
10349 return obj->LookupAccessor(name, flag->value() == 0);
10350}
10351
10352
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010353#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010354RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010355 ASSERT(args.length() == 0);
10356 return Execution::DebugBreakHelper();
10357}
10358
10359
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010360// Helper functions for wrapping and unwrapping stack frame ids.
10361static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010362 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010363 return Smi::FromInt(id >> 2);
10364}
10365
10366
10367static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10368 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10369}
10370
10371
10372// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010373// args[0]: debug event listener function to set or null or undefined for
10374// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010375// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010376RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010377 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010378 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10379 args[0]->IsUndefined() ||
10380 args[0]->IsNull());
10381 Handle<Object> callback = args.at<Object>(0);
10382 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010383 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010384
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010385 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010386}
10387
10388
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010389RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010390 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010391 isolate->stack_guard()->DebugBreak();
10392 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010393}
10394
10395
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010396static MaybeObject* DebugLookupResultValue(Heap* heap,
10397 Object* receiver,
10398 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010399 LookupResult* result,
10400 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010401 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010402 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010403 case NORMAL:
10404 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010405 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010406 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010407 }
10408 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010409 case FIELD:
10410 value =
10411 JSObject::cast(
10412 result->holder())->FastPropertyAt(result->GetFieldIndex());
10413 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010414 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010415 }
10416 return value;
10417 case CONSTANT_FUNCTION:
10418 return result->GetConstantFunction();
10419 case CALLBACKS: {
10420 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010421 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010422 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10423 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010424 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010425 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010426 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010427 maybe_value = heap->isolate()->pending_exception();
10428 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010429 if (caught_exception != NULL) {
10430 *caught_exception = true;
10431 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010432 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010433 }
10434 return value;
10435 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010436 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010437 }
10438 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010439 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010440 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010441 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010442 case CONSTANT_TRANSITION:
10443 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010444 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010445 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010446 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010447 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010448 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010449 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010450 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010451}
10452
10453
ager@chromium.org32912102009-01-16 10:38:43 +000010454// Get debugger related details for an object property.
10455// args[0]: object holding property
10456// args[1]: name of the property
10457//
10458// The array returned contains the following information:
10459// 0: Property value
10460// 1: Property details
10461// 2: Property value is exception
10462// 3: Getter function if defined
10463// 4: Setter function if defined
10464// Items 2-4 are only filled if the property has either a getter or a setter
10465// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010466RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010467 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010468
10469 ASSERT(args.length() == 2);
10470
10471 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10472 CONVERT_ARG_CHECKED(String, name, 1);
10473
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010474 // Make sure to set the current context to the context before the debugger was
10475 // entered (if the debugger is entered). The reason for switching context here
10476 // is that for some property lookups (accessors and interceptors) callbacks
10477 // into the embedding application can occour, and the embedding application
10478 // could have the assumption that its own global context is the current
10479 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010480 SaveContext save(isolate);
10481 if (isolate->debug()->InDebugger()) {
10482 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010483 }
10484
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010485 // Skip the global proxy as it has no properties and always delegates to the
10486 // real global object.
10487 if (obj->IsJSGlobalProxy()) {
10488 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10489 }
10490
10491
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010492 // Check if the name is trivially convertible to an index and get the element
10493 // if so.
10494 uint32_t index;
10495 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010496 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010497 Object* element_or_char;
10498 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010499 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010500 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10501 return maybe_element_or_char;
10502 }
10503 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010504 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010505 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010506 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010507 }
10508
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010509 // Find the number of objects making up this.
10510 int length = LocalPrototypeChainLength(*obj);
10511
10512 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010513 Handle<JSObject> jsproto = obj;
10514 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010515 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010516 jsproto->LocalLookup(*name, &result);
10517 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010518 // LookupResult is not GC safe as it holds raw object pointers.
10519 // GC can happen later in this code so put the required fields into
10520 // local variables using handles when required for later use.
10521 PropertyType result_type = result.type();
10522 Handle<Object> result_callback_obj;
10523 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010524 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10525 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010526 }
10527 Smi* property_details = result.GetPropertyDetails().AsSmi();
10528 // DebugLookupResultValue can cause GC so details from LookupResult needs
10529 // to be copied to handles before this.
10530 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010531 Object* raw_value;
10532 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010533 DebugLookupResultValue(isolate->heap(), *obj, *name,
10534 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010535 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10536 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010537 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010538
10539 // If the callback object is a fixed array then it contains JavaScript
10540 // getter and/or setter.
10541 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10542 result_callback_obj->IsFixedArray();
10543 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010544 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010545 details->set(0, *value);
10546 details->set(1, property_details);
10547 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010548 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010549 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10550 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10551 }
10552
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010553 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010554 }
10555 if (i < length - 1) {
10556 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10557 }
10558 }
10559
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010560 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010561}
10562
10563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010564RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010565 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010566
10567 ASSERT(args.length() == 2);
10568
10569 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10570 CONVERT_ARG_CHECKED(String, name, 1);
10571
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010572 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010573 obj->Lookup(*name, &result);
10574 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010575 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010576 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010577 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010578}
10579
10580
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010581// Return the property type calculated from the property details.
10582// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010583RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010584 ASSERT(args.length() == 1);
10585 CONVERT_CHECKED(Smi, details, args[0]);
10586 PropertyType type = PropertyDetails(details).type();
10587 return Smi::FromInt(static_cast<int>(type));
10588}
10589
10590
10591// Return the property attribute calculated from the property details.
10592// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010593RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010594 ASSERT(args.length() == 1);
10595 CONVERT_CHECKED(Smi, details, args[0]);
10596 PropertyAttributes attributes = PropertyDetails(details).attributes();
10597 return Smi::FromInt(static_cast<int>(attributes));
10598}
10599
10600
10601// Return the property insertion index calculated from the property details.
10602// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010603RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010604 ASSERT(args.length() == 1);
10605 CONVERT_CHECKED(Smi, details, args[0]);
10606 int index = PropertyDetails(details).index();
10607 return Smi::FromInt(index);
10608}
10609
10610
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010611// Return property value from named interceptor.
10612// args[0]: object
10613// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010614RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010615 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010616 ASSERT(args.length() == 2);
10617 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10618 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10619 CONVERT_ARG_CHECKED(String, name, 1);
10620
10621 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010622 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010623}
10624
10625
10626// Return element value from indexed interceptor.
10627// args[0]: object
10628// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010629RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010630 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010631 ASSERT(args.length() == 2);
10632 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10633 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10634 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10635
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010636 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010637}
10638
10639
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010640RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010641 ASSERT(args.length() >= 1);
10642 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010643 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010644 if (isolate->debug()->break_id() == 0 ||
10645 break_id != isolate->debug()->break_id()) {
10646 return isolate->Throw(
10647 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010648 }
10649
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010650 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010651}
10652
10653
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010654RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010655 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010656 ASSERT(args.length() == 1);
10657
10658 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010659 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010660 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10661 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010662 if (!maybe_result->ToObject(&result)) return maybe_result;
10663 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010664
10665 // Count all frames which are relevant to debugging stack trace.
10666 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010667 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010668 if (id == StackFrame::NO_ID) {
10669 // If there is no JavaScript stack frame count is 0.
10670 return Smi::FromInt(0);
10671 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010672
10673 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10674 n += it.frame()->GetInlineCount();
10675 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010676 return Smi::FromInt(n);
10677}
10678
10679
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010680class FrameInspector {
10681 public:
10682 FrameInspector(JavaScriptFrame* frame,
10683 int inlined_frame_index,
10684 Isolate* isolate)
10685 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10686 // Calculate the deoptimized frame.
10687 if (frame->is_optimized()) {
10688 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10689 frame, inlined_frame_index, isolate);
10690 }
10691 has_adapted_arguments_ = frame_->has_adapted_arguments();
10692 is_optimized_ = frame_->is_optimized();
10693 }
10694
10695 ~FrameInspector() {
10696 // Get rid of the calculated deoptimized frame if any.
10697 if (deoptimized_frame_ != NULL) {
10698 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10699 isolate_);
10700 }
10701 }
10702
10703 int GetParametersCount() {
10704 return is_optimized_
10705 ? deoptimized_frame_->parameters_count()
10706 : frame_->ComputeParametersCount();
10707 }
10708 int expression_count() { return deoptimized_frame_->expression_count(); }
10709 Object* GetFunction() {
10710 return is_optimized_
10711 ? deoptimized_frame_->GetFunction()
10712 : frame_->function();
10713 }
10714 Object* GetParameter(int index) {
10715 return is_optimized_
10716 ? deoptimized_frame_->GetParameter(index)
10717 : frame_->GetParameter(index);
10718 }
10719 Object* GetExpression(int index) {
10720 return is_optimized_
10721 ? deoptimized_frame_->GetExpression(index)
10722 : frame_->GetExpression(index);
10723 }
10724
10725 // To inspect all the provided arguments the frame might need to be
10726 // replaced with the arguments frame.
10727 void SetArgumentsFrame(JavaScriptFrame* frame) {
10728 ASSERT(has_adapted_arguments_);
10729 frame_ = frame;
10730 is_optimized_ = frame_->is_optimized();
10731 ASSERT(!is_optimized_);
10732 }
10733
10734 private:
10735 JavaScriptFrame* frame_;
10736 DeoptimizedFrameInfo* deoptimized_frame_;
10737 Isolate* isolate_;
10738 bool is_optimized_;
10739 bool has_adapted_arguments_;
10740
10741 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10742};
10743
10744
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010745static const int kFrameDetailsFrameIdIndex = 0;
10746static const int kFrameDetailsReceiverIndex = 1;
10747static const int kFrameDetailsFunctionIndex = 2;
10748static const int kFrameDetailsArgumentCountIndex = 3;
10749static const int kFrameDetailsLocalCountIndex = 4;
10750static const int kFrameDetailsSourcePositionIndex = 5;
10751static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010752static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010753static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010754static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010755
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010756
10757static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10758 JavaScriptFrame* frame) {
10759 SaveContext* save = isolate->save_context();
10760 while (save != NULL && !save->IsBelowFrame(frame)) {
10761 save = save->prev();
10762 }
10763 ASSERT(save != NULL);
10764 return save;
10765}
10766
10767
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010768// Return an array with frame details
10769// args[0]: number: break id
10770// args[1]: number: frame index
10771//
10772// The array returned contains the following information:
10773// 0: Frame id
10774// 1: Receiver
10775// 2: Function
10776// 3: Argument count
10777// 4: Local count
10778// 5: Source position
10779// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010780// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010781// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010782// Arguments name, value
10783// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010784// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010785RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010786 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010787 ASSERT(args.length() == 2);
10788
10789 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010790 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010791 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10792 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010793 if (!maybe_check->ToObject(&check)) return maybe_check;
10794 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010795 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010796 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010797
10798 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010799 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010800 if (id == StackFrame::NO_ID) {
10801 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010802 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010803 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010804
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010805 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010806
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010807 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010808 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010809 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010810 if (index < count + it.frame()->GetInlineCount()) break;
10811 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010812 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010813 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010814
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010815 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010816 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010817 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010818 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010819 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010820
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010821 // Traverse the saved contexts chain to find the active context for the
10822 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010823 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010824
10825 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010826 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010827
10828 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010829 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010830 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010831
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010832 // Check for constructor frame. Inlined frames cannot be construct calls.
10833 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010834 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010835 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010836
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010837 // Get scope info and read from it for local variable information.
10838 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010839 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010840 Handle<ScopeInfo> scope_info(shared->scope_info());
10841 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010842
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010843 // Get the locals names and values into a temporary array.
10844 //
10845 // TODO(1240907): Hide compiler-introduced stack variables
10846 // (e.g. .result)? For users of the debugger, they will probably be
10847 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010848 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010849 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010850
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010851 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010852 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010853 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010854 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010855 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010856 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010857 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010858 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010859 // Get the context containing declarations.
10860 Handle<Context> context(
10861 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010862 for (; i < scope_info->LocalCount(); ++i) {
10863 Handle<String> name(scope_info->LocalName(i));
10864 VariableMode mode;
10865 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010866 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010867 locals->set(i * 2 + 1, context->get(
10868 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010869 }
10870 }
10871
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010872 // Check whether this frame is positioned at return. If not top
10873 // frame or if the frame is optimized it cannot be at a return.
10874 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010875 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010876 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010877 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010878
10879 // If positioned just before return find the value to be returned and add it
10880 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010881 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010882 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010883 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010884 Address internal_frame_sp = NULL;
10885 while (!it2.done()) {
10886 if (it2.frame()->is_internal()) {
10887 internal_frame_sp = it2.frame()->sp();
10888 } else {
10889 if (it2.frame()->is_java_script()) {
10890 if (it2.frame()->id() == it.frame()->id()) {
10891 // The internal frame just before the JavaScript frame contains the
10892 // value to return on top. A debug break at return will create an
10893 // internal frame to store the return value (eax/rax/r0) before
10894 // entering the debug break exit frame.
10895 if (internal_frame_sp != NULL) {
10896 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010897 Handle<Object>(Memory::Object_at(internal_frame_sp),
10898 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010899 break;
10900 }
10901 }
10902 }
10903
10904 // Indicate that the previous frame was not an internal frame.
10905 internal_frame_sp = NULL;
10906 }
10907 it2.Advance();
10908 }
10909 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010910
10911 // Now advance to the arguments adapter frame (if any). It contains all
10912 // the provided parameters whereas the function frame always have the number
10913 // of arguments matching the functions parameters. The rest of the
10914 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010915 if (it.frame()->has_adapted_arguments()) {
10916 it.AdvanceToArgumentsFrame();
10917 frame_inspector.SetArgumentsFrame(it.frame());
10918 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010919
10920 // Find the number of arguments to fill. At least fill the number of
10921 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010922 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010923 if (argument_count < frame_inspector.GetParametersCount()) {
10924 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010925 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010926#ifdef DEBUG
10927 if (it.frame()->is_optimized()) {
10928 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10929 }
10930#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010931
10932 // Calculate the size of the result.
10933 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010934 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010935 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010936 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010937
10938 // Add the frame id.
10939 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10940
10941 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010942 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010943
10944 // Add the arguments count.
10945 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10946
10947 // Add the locals count
10948 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010949 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010950
10951 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010952 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010953 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10954 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010955 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010956 }
10957
10958 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010959 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010960
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010961 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010962 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010963
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010964 // Add flags to indicate information on whether this frame is
10965 // bit 0: invoked in the debugger context.
10966 // bit 1: optimized frame.
10967 // bit 2: inlined in optimized frame
10968 int flags = 0;
10969 if (*save->context() == *isolate->debug()->debug_context()) {
10970 flags |= 1 << 0;
10971 }
10972 if (it.frame()->is_optimized()) {
10973 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010974 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010975 }
10976 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010977
10978 // Fill the dynamic part.
10979 int details_index = kFrameDetailsFirstDynamicIndex;
10980
10981 // Add arguments name and value.
10982 for (int i = 0; i < argument_count; i++) {
10983 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010984 if (i < scope_info->ParameterCount()) {
10985 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010986 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010987 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010988 }
10989
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010990 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010991 if (i < it.frame()->ComputeParametersCount()) {
10992 // Get the value from the stack.
10993 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010994 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010995 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010996 }
10997 }
10998
10999 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011000 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011001 details->set(details_index++, locals->get(i));
11002 }
11003
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011004 // Add the value being returned.
11005 if (at_return) {
11006 details->set(details_index++, *return_value);
11007 }
11008
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011009 // Add the receiver (same as in function frame).
11010 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
11011 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011012 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000011013 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
11014 // If the receiver is not a JSObject and the function is not a
11015 // builtin or strict-mode we have hit an optimization where a
11016 // value object is not converted into a wrapped JS objects. To
11017 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011018 // by creating correct wrapper object based on the calling frame's
11019 // global context.
11020 it.Advance();
11021 Handle<Context> calling_frames_global_context(
11022 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011023 receiver =
11024 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011025 }
11026 details->set(kFrameDetailsReceiverIndex, *receiver);
11027
11028 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011029 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011030}
11031
11032
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011033// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011034static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011035 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011036 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011037 Handle<Context> context,
11038 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011039 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011040 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11041 VariableMode mode;
11042 InitializationFlag init_flag;
11043 int context_index = scope_info->ContextSlotIndex(
11044 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011045
whesse@chromium.org7b260152011-06-20 15:33:18 +000011046 RETURN_IF_EMPTY_HANDLE_VALUE(
11047 isolate,
11048 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011049 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000011050 Handle<Object>(context->get(context_index), isolate),
11051 NONE,
11052 kNonStrictMode),
11053 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011054 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011055
11056 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011057}
11058
11059
11060// Create a plain JSObject which materializes the local scope for the specified
11061// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011062static Handle<JSObject> MaterializeLocalScope(
11063 Isolate* isolate,
11064 JavaScriptFrame* frame,
11065 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011066 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011067 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011068 Handle<ScopeInfo> scope_info(shared->scope_info());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011069 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011070
11071 // Allocate and initialize a JSObject with all the arguments, stack locals
11072 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011073 Handle<JSObject> local_scope =
11074 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011075
11076 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011077 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011078 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011079 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011080 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011081 Handle<String>(scope_info->ParameterName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011082 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011083 NONE,
11084 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011085 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011086 }
11087
11088 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011089 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011090 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011091 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011092 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011093 Handle<String>(scope_info->StackLocalName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011094 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011095 NONE,
11096 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011097 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011098 }
11099
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011100 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011101 // Third fill all context locals.
11102 Handle<Context> frame_context(Context::cast(frame->context()));
11103 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011104 if (!CopyContextLocalsToScopeObject(
11105 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011106 return Handle<JSObject>();
11107 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011108
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011109 // Finally copy any properties from the function context extension.
11110 // These will be variables introduced by eval.
11111 if (function_context->closure() == *function) {
11112 if (function_context->has_extension() &&
11113 !function_context->IsGlobalContext()) {
11114 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011115 bool threw = false;
11116 Handle<FixedArray> keys =
11117 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11118 if (threw) return Handle<JSObject>();
11119
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011120 for (int i = 0; i < keys->length(); i++) {
11121 // Names of variables introduced by eval are strings.
11122 ASSERT(keys->get(i)->IsString());
11123 Handle<String> key(String::cast(keys->get(i)));
11124 RETURN_IF_EMPTY_HANDLE_VALUE(
11125 isolate,
11126 SetProperty(local_scope,
11127 key,
11128 GetProperty(ext, key),
11129 NONE,
11130 kNonStrictMode),
11131 Handle<JSObject>());
11132 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011133 }
11134 }
11135 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011136
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011137 return local_scope;
11138}
11139
11140
11141// Create a plain JSObject which materializes the closure content for the
11142// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011143static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11144 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011145 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011146
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011147 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011148 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011149
11150 // Allocate and initialize a JSObject with all the content of theis function
11151 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011152 Handle<JSObject> closure_scope =
11153 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011154
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011155 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011156 if (!CopyContextLocalsToScopeObject(
11157 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011158 return Handle<JSObject>();
11159 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011160
11161 // Finally copy any properties from the function context extension. This will
11162 // be variables introduced by eval.
11163 if (context->has_extension()) {
11164 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011165 bool threw = false;
11166 Handle<FixedArray> keys =
11167 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11168 if (threw) return Handle<JSObject>();
11169
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011170 for (int i = 0; i < keys->length(); i++) {
11171 // Names of variables introduced by eval are strings.
11172 ASSERT(keys->get(i)->IsString());
11173 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011174 RETURN_IF_EMPTY_HANDLE_VALUE(
11175 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011176 SetProperty(closure_scope,
11177 key,
11178 GetProperty(ext, key),
11179 NONE,
11180 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011181 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011182 }
11183 }
11184
11185 return closure_scope;
11186}
11187
11188
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011189// Create a plain JSObject which materializes the scope for the specified
11190// catch context.
11191static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11192 Handle<Context> context) {
11193 ASSERT(context->IsCatchContext());
11194 Handle<String> name(String::cast(context->extension()));
11195 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11196 Handle<JSObject> catch_scope =
11197 isolate->factory()->NewJSObject(isolate->object_function());
11198 RETURN_IF_EMPTY_HANDLE_VALUE(
11199 isolate,
11200 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11201 Handle<JSObject>());
11202 return catch_scope;
11203}
11204
11205
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011206// Create a plain JSObject which materializes the block scope for the specified
11207// block context.
11208static Handle<JSObject> MaterializeBlockScope(
11209 Isolate* isolate,
11210 Handle<Context> context) {
11211 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011212 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011213
11214 // Allocate and initialize a JSObject with all the arguments, stack locals
11215 // heap locals and extension properties of the debugged function.
11216 Handle<JSObject> block_scope =
11217 isolate->factory()->NewJSObject(isolate->object_function());
11218
11219 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011220 if (!CopyContextLocalsToScopeObject(
11221 isolate, scope_info, context, block_scope)) {
11222 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011223 }
11224
11225 return block_scope;
11226}
11227
11228
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011229// Iterate over the actual scopes visible from a stack frame. The iteration
11230// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011231// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011232// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011233class ScopeIterator {
11234 public:
11235 enum ScopeType {
11236 ScopeTypeGlobal = 0,
11237 ScopeTypeLocal,
11238 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011239 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011240 ScopeTypeCatch,
11241 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011242 };
11243
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011244 ScopeIterator(Isolate* isolate,
11245 JavaScriptFrame* frame,
11246 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011247 : isolate_(isolate),
11248 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011249 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011250 function_(JSFunction::cast(frame->function())),
11251 context_(Context::cast(frame->context())),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011252 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011253
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011254 // Catch the case when the debugger stops in an internal function.
11255 Handle<SharedFunctionInfo> shared_info(function_->shared());
11256 if (shared_info->script() == isolate->heap()->undefined_value()) {
11257 while (context_->closure() == *function_) {
11258 context_ = Handle<Context>(context_->previous(), isolate_);
11259 }
11260 return;
11261 }
11262
11263 // Check whether we are in global code or function code. If there is a stack
11264 // slot for .result then this function has been created for evaluating
11265 // global code and it is not a real function.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011266 // Checking for the existence of .result seems fragile, but the scope info
11267 // saved with the code object does not otherwise have that information.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011268 int index = shared_info->scope_info()->
lrn@chromium.org34e60782011-09-15 07:25:40 +000011269 StackSlotIndex(isolate_->heap()->result_symbol());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011270
11271 // Reparse the code and analyze the scopes.
11272 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11273 Handle<Script> script(Script::cast(shared_info->script()));
11274 Scope* scope;
lrn@chromium.org34e60782011-09-15 07:25:40 +000011275 if (index >= 0) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011276 // Global code
11277 CompilationInfo info(script);
11278 info.MarkAsGlobal();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011279 CHECK(ParserApi::Parse(&info));
11280 CHECK(Scope::Analyze(&info));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011281 scope = info.function()->scope();
11282 } else {
11283 // Function code
11284 CompilationInfo info(shared_info);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011285 CHECK(ParserApi::Parse(&info));
11286 CHECK(Scope::Analyze(&info));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011287 scope = info.function()->scope();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011288 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011289
11290 // Retrieve the scope chain for the current position.
11291 int statement_position =
11292 shared_info->code()->SourceStatementPosition(frame_->pc());
11293 scope->GetNestedScopeChain(&nested_scope_chain_, statement_position);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011294 }
11295
11296 // More scopes?
11297 bool Done() { return context_.is_null(); }
11298
11299 // Move to the next scope.
11300 void Next() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011301 ScopeType scope_type = Type();
11302 if (scope_type == ScopeTypeGlobal) {
11303 // The global scope is always the last in the chain.
11304 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011305 context_ = Handle<Context>();
11306 return;
11307 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011308 if (nested_scope_chain_.is_empty()) {
11309 context_ = Handle<Context>(context_->previous(), isolate_);
11310 } else {
11311 if (nested_scope_chain_.last()->HasContext()) {
11312 context_ = Handle<Context>(context_->previous(), isolate_);
11313 }
11314 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011315 }
11316 }
11317
11318 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011319 ScopeType Type() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011320 if (!nested_scope_chain_.is_empty()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011321 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011322 switch (scope_info->Type()) {
11323 case FUNCTION_SCOPE:
11324 ASSERT(context_->IsFunctionContext() ||
11325 !scope_info->HasContext());
11326 return ScopeTypeLocal;
11327 case GLOBAL_SCOPE:
11328 ASSERT(context_->IsGlobalContext());
11329 return ScopeTypeGlobal;
11330 case WITH_SCOPE:
11331 ASSERT(context_->IsWithContext());
11332 return ScopeTypeWith;
11333 case CATCH_SCOPE:
11334 ASSERT(context_->IsCatchContext());
11335 return ScopeTypeCatch;
11336 case BLOCK_SCOPE:
11337 ASSERT(!scope_info->HasContext() ||
11338 context_->IsBlockContext());
11339 return ScopeTypeBlock;
11340 case EVAL_SCOPE:
11341 UNREACHABLE();
11342 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011343 }
11344 if (context_->IsGlobalContext()) {
11345 ASSERT(context_->global()->IsGlobalObject());
11346 return ScopeTypeGlobal;
11347 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011348 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011349 return ScopeTypeClosure;
11350 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011351 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011352 return ScopeTypeCatch;
11353 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011354 if (context_->IsBlockContext()) {
11355 return ScopeTypeBlock;
11356 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011357 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011358 return ScopeTypeWith;
11359 }
11360
11361 // Return the JavaScript object with the content of the current scope.
11362 Handle<JSObject> ScopeObject() {
11363 switch (Type()) {
11364 case ScopeIterator::ScopeTypeGlobal:
11365 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011366 case ScopeIterator::ScopeTypeLocal:
11367 // Materialize the content of the local scope into a JSObject.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011368 ASSERT(nested_scope_chain_.length() == 1);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011369 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011370 case ScopeIterator::ScopeTypeWith:
11371 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011372 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11373 case ScopeIterator::ScopeTypeCatch:
11374 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011375 case ScopeIterator::ScopeTypeClosure:
11376 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011377 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011378 case ScopeIterator::ScopeTypeBlock:
11379 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011380 }
11381 UNREACHABLE();
11382 return Handle<JSObject>();
11383 }
11384
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011385 Handle<ScopeInfo> CurrentScopeInfo() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011386 if (!nested_scope_chain_.is_empty()) {
11387 return nested_scope_chain_.last();
11388 } else if (context_->IsBlockContext()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011389 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011390 } else if (context_->IsFunctionContext()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011391 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011392 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011393 return Handle<ScopeInfo>::null();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011394 }
11395
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011396 // Return the context for this scope. For the local context there might not
11397 // be an actual context.
11398 Handle<Context> CurrentContext() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011399 if (Type() == ScopeTypeGlobal ||
11400 nested_scope_chain_.is_empty()) {
11401 return context_;
11402 } else if (nested_scope_chain_.last()->HasContext()) {
11403 return context_;
11404 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011405 return Handle<Context>();
11406 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011407 }
11408
11409#ifdef DEBUG
11410 // Debug print of the content of the current scope.
11411 void DebugPrint() {
11412 switch (Type()) {
11413 case ScopeIterator::ScopeTypeGlobal:
11414 PrintF("Global:\n");
11415 CurrentContext()->Print();
11416 break;
11417
11418 case ScopeIterator::ScopeTypeLocal: {
11419 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011420 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011421 if (!CurrentContext().is_null()) {
11422 CurrentContext()->Print();
11423 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011424 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011425 if (extension->IsJSContextExtensionObject()) {
11426 extension->Print();
11427 }
11428 }
11429 }
11430 break;
11431 }
11432
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011433 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011434 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011435 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011436 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011437
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011438 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011439 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011440 CurrentContext()->extension()->Print();
11441 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011442 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011443
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011444 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011445 PrintF("Closure:\n");
11446 CurrentContext()->Print();
11447 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011448 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011449 if (extension->IsJSContextExtensionObject()) {
11450 extension->Print();
11451 }
11452 }
11453 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011454
11455 default:
11456 UNREACHABLE();
11457 }
11458 PrintF("\n");
11459 }
11460#endif
11461
11462 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011463 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011464 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011465 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011466 Handle<JSFunction> function_;
11467 Handle<Context> context_;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011468 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011469
11470 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11471};
11472
11473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011474RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011475 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011476 ASSERT(args.length() == 2);
11477
11478 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011479 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011480 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11481 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011482 if (!maybe_check->ToObject(&check)) return maybe_check;
11483 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011484 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11485
11486 // Get the frame where the debugging is performed.
11487 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011488 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011489 JavaScriptFrame* frame = it.frame();
11490
11491 // Count the visible scopes.
11492 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011493 for (ScopeIterator it(isolate, frame, 0);
11494 !it.Done();
11495 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011496 n++;
11497 }
11498
11499 return Smi::FromInt(n);
11500}
11501
11502
11503static const int kScopeDetailsTypeIndex = 0;
11504static const int kScopeDetailsObjectIndex = 1;
11505static const int kScopeDetailsSize = 2;
11506
11507// Return an array with scope details
11508// args[0]: number: break id
11509// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011510// args[2]: number: inlined frame index
11511// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011512//
11513// The array returned contains the following information:
11514// 0: Scope type
11515// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011516RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011517 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011518 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011519
11520 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011521 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011522 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11523 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011524 if (!maybe_check->ToObject(&check)) return maybe_check;
11525 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011526 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011527 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11528 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011529
11530 // Get the frame where the debugging is performed.
11531 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011532 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011533 JavaScriptFrame* frame = frame_it.frame();
11534
11535 // Find the requested scope.
11536 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011537 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011538 for (; !it.Done() && n < index; it.Next()) {
11539 n++;
11540 }
11541 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011542 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011543 }
11544
11545 // Calculate the size of the result.
11546 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011547 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011548
11549 // Fill in scope details.
11550 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011551 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011552 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011553 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011554
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011555 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011556}
11557
11558
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011559RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011560 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011561 ASSERT(args.length() == 0);
11562
11563#ifdef DEBUG
11564 // Print the scopes for the top frame.
11565 StackFrameLocator locator;
11566 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011567 for (ScopeIterator it(isolate, frame, 0);
11568 !it.Done();
11569 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011570 it.DebugPrint();
11571 }
11572#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011573 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011574}
11575
11576
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011577RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011578 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011579 ASSERT(args.length() == 1);
11580
11581 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011582 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011583 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11584 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011585 if (!maybe_result->ToObject(&result)) return maybe_result;
11586 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011587
11588 // Count all archived V8 threads.
11589 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011590 for (ThreadState* thread =
11591 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011592 thread != NULL;
11593 thread = thread->Next()) {
11594 n++;
11595 }
11596
11597 // Total number of threads is current thread and archived threads.
11598 return Smi::FromInt(n + 1);
11599}
11600
11601
11602static const int kThreadDetailsCurrentThreadIndex = 0;
11603static const int kThreadDetailsThreadIdIndex = 1;
11604static const int kThreadDetailsSize = 2;
11605
11606// Return an array with thread details
11607// args[0]: number: break id
11608// args[1]: number: thread index
11609//
11610// The array returned contains the following information:
11611// 0: Is current thread?
11612// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011613RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011614 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011615 ASSERT(args.length() == 2);
11616
11617 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011618 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011619 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11620 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011621 if (!maybe_check->ToObject(&check)) return maybe_check;
11622 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011623 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11624
11625 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011626 Handle<FixedArray> details =
11627 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011628
11629 // Thread index 0 is current thread.
11630 if (index == 0) {
11631 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011632 details->set(kThreadDetailsCurrentThreadIndex,
11633 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011634 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011635 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011636 } else {
11637 // Find the thread with the requested index.
11638 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011639 ThreadState* thread =
11640 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011641 while (index != n && thread != NULL) {
11642 thread = thread->Next();
11643 n++;
11644 }
11645 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011646 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011647 }
11648
11649 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011650 details->set(kThreadDetailsCurrentThreadIndex,
11651 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011652 details->set(kThreadDetailsThreadIdIndex,
11653 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011654 }
11655
11656 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011657 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011658}
11659
11660
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011661// Sets the disable break state
11662// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011663RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011664 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011665 ASSERT(args.length() == 1);
11666 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011667 isolate->debug()->set_disable_break(disable_break);
11668 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011669}
11670
11671
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011672RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011673 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011674 ASSERT(args.length() == 1);
11675
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011676 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11677 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011678 // Find the number of break points
11679 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011680 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011681 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011682 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011683 Handle<FixedArray>::cast(break_locations));
11684}
11685
11686
11687// Set a break point in a function
11688// args[0]: function
11689// args[1]: number: break source position (within the function source)
11690// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011691RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011692 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011693 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011694 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11695 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011696 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11697 RUNTIME_ASSERT(source_position >= 0);
11698 Handle<Object> break_point_object_arg = args.at<Object>(2);
11699
11700 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011701 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11702 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011703
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011704 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011705}
11706
11707
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011708Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11709 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011710 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011711 // Iterate the heap looking for SharedFunctionInfo generated from the
11712 // script. The inner most SharedFunctionInfo containing the source position
11713 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011714 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011715 // which is found is not compiled it is compiled and the heap is iterated
11716 // again as the compilation might create inner functions from the newly
11717 // compiled function and the actual requested break point might be in one of
11718 // these functions.
11719 bool done = false;
11720 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011721 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011722 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011723 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011724 { // Extra scope for iterator and no-allocation.
11725 isolate->heap()->EnsureHeapIsIterable();
11726 AssertNoAllocation no_alloc_during_heap_iteration;
11727 HeapIterator iterator;
11728 for (HeapObject* obj = iterator.next();
11729 obj != NULL; obj = iterator.next()) {
11730 if (obj->IsSharedFunctionInfo()) {
11731 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11732 if (shared->script() == *script) {
11733 // If the SharedFunctionInfo found has the requested script data and
11734 // contains the source position it is a candidate.
11735 int start_position = shared->function_token_position();
11736 if (start_position == RelocInfo::kNoPosition) {
11737 start_position = shared->start_position();
11738 }
11739 if (start_position <= position &&
11740 position <= shared->end_position()) {
11741 // If there is no candidate or this function is within the current
11742 // candidate this is the new candidate.
11743 if (target.is_null()) {
11744 target_start_position = start_position;
11745 target = shared;
11746 } else {
11747 if (target_start_position == start_position &&
11748 shared->end_position() == target->end_position()) {
11749 // If a top-level function contain only one function
11750 // declartion the source for the top-level and the
11751 // function is the same. In that case prefer the non
11752 // top-level function.
11753 if (!shared->is_toplevel()) {
11754 target_start_position = start_position;
11755 target = shared;
11756 }
11757 } else if (target_start_position <= start_position &&
11758 shared->end_position() <= target->end_position()) {
11759 // This containment check includes equality as a function
11760 // inside a top-level function can share either start or end
11761 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011762 target_start_position = start_position;
11763 target = shared;
11764 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011765 }
11766 }
11767 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011768 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011769 } // End for loop.
11770 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011771
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011772 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011773 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011774 }
11775
11776 // If the candidate found is compiled we are done. NOTE: when lazy
11777 // compilation of inner functions is introduced some additional checking
11778 // needs to be done here to compile inner functions.
11779 done = target->is_compiled();
11780 if (!done) {
11781 // If the candidate is not compiled compile it to reveal any inner
11782 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011783 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011784 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011785 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011786
11787 return *target;
11788}
11789
11790
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011791// Changes the state of a break point in a script and returns source position
11792// where break point was set. NOTE: Regarding performance see the NOTE for
11793// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011794// args[0]: script to set break point in
11795// args[1]: number: break source position (within the script source)
11796// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011797RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011798 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011799 ASSERT(args.length() == 3);
11800 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11801 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11802 RUNTIME_ASSERT(source_position >= 0);
11803 Handle<Object> break_point_object_arg = args.at<Object>(2);
11804
11805 // Get the script from the script wrapper.
11806 RUNTIME_ASSERT(wrapper->value()->IsScript());
11807 Handle<Script> script(Script::cast(wrapper->value()));
11808
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011809 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011810 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011811 if (!result->IsUndefined()) {
11812 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11813 // Find position within function. The script position might be before the
11814 // source position of the first function.
11815 int position;
11816 if (shared->start_position() > source_position) {
11817 position = 0;
11818 } else {
11819 position = source_position - shared->start_position();
11820 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011821 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011822 position += shared->start_position();
11823 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011824 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011825 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011826}
11827
11828
11829// Clear a break point
11830// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011831RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011832 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011833 ASSERT(args.length() == 1);
11834 Handle<Object> break_point_object_arg = args.at<Object>(0);
11835
11836 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011837 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011838
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011839 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011840}
11841
11842
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011843// Change the state of break on exceptions.
11844// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11845// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011846RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011847 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011848 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011849 RUNTIME_ASSERT(args[0]->IsNumber());
11850 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011851
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011852 // If the number doesn't match an enum value, the ChangeBreakOnException
11853 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011854 ExceptionBreakType type =
11855 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011856 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011857 isolate->debug()->ChangeBreakOnException(type, enable);
11858 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011859}
11860
11861
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011862// Returns the state of break on exceptions
11863// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011864RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011865 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011866 ASSERT(args.length() == 1);
11867 RUNTIME_ASSERT(args[0]->IsNumber());
11868
11869 ExceptionBreakType type =
11870 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011871 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011872 return Smi::FromInt(result);
11873}
11874
11875
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011876// Prepare for stepping
11877// args[0]: break id for checking execution state
11878// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011879// args[2]: number of times to perform the step, for step out it is the number
11880// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011881RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011882 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011883 ASSERT(args.length() == 3);
11884 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011885 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011886 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11887 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011888 if (!maybe_check->ToObject(&check)) return maybe_check;
11889 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011890 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011891 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011892 }
11893
11894 // Get the step action and check validity.
11895 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11896 if (step_action != StepIn &&
11897 step_action != StepNext &&
11898 step_action != StepOut &&
11899 step_action != StepInMin &&
11900 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011901 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011902 }
11903
11904 // Get the number of steps.
11905 int step_count = NumberToInt32(args[2]);
11906 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011907 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011908 }
11909
ager@chromium.orga1645e22009-09-09 19:27:10 +000011910 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011911 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011912
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011913 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011914 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11915 step_count);
11916 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011917}
11918
11919
11920// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011921RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011922 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011923 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011924 isolate->debug()->ClearStepping();
11925 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011926}
11927
11928
11929// Creates a copy of the with context chain. The copy of the context chain is
11930// is linked to the function context supplied.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011931static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11932 Handle<JSFunction> function,
11933 Handle<Context> base,
11934 JavaScriptFrame* frame,
11935 int inlined_frame_index) {
11936 HandleScope scope(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011937 List<Handle<ScopeInfo> > scope_chain;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011938 List<Handle<Context> > context_chain;
11939
11940 ScopeIterator it(isolate, frame, inlined_frame_index);
11941 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11942 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11943 ASSERT(!it.Done());
11944 scope_chain.Add(it.CurrentScopeInfo());
11945 context_chain.Add(it.CurrentContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011946 }
11947
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011948 // At the end of the chain. Return the base context to link to.
11949 Handle<Context> context = base;
11950
11951 // Iteratively copy and or materialize the nested contexts.
11952 while (!scope_chain.is_empty()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011953 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011954 Handle<Context> current = context_chain.RemoveLast();
11955 ASSERT(!(scope_info->HasContext() & current.is_null()));
11956
11957 if (scope_info->Type() == CATCH_SCOPE) {
11958 Handle<String> name(String::cast(current->extension()));
11959 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11960 context =
11961 isolate->factory()->NewCatchContext(function,
11962 context,
11963 name,
11964 thrown_object);
11965 } else if (scope_info->Type() == BLOCK_SCOPE) {
11966 // Materialize the contents of the block scope into a JSObject.
11967 Handle<JSObject> block_scope_object =
11968 MaterializeBlockScope(isolate, current);
11969 if (block_scope_object.is_null()) {
11970 return Handle<Context>::null();
11971 }
11972 // Allocate a new function context for the debug evaluation and set the
11973 // extension object.
11974 Handle<Context> new_context =
11975 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11976 function);
11977 new_context->set_extension(*block_scope_object);
11978 new_context->set_previous(*context);
11979 context = new_context;
11980 } else {
11981 ASSERT(scope_info->Type() == WITH_SCOPE);
11982 ASSERT(current->IsWithContext());
11983 Handle<JSObject> extension(JSObject::cast(current->extension()));
11984 context =
11985 isolate->factory()->NewWithContext(function, context, extension);
danno@chromium.orgb6451162011-08-17 14:33:23 +000011986 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011987 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011988
11989 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011990}
11991
11992
11993// Helper function to find or create the arguments object for
11994// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011995static Handle<Object> GetArgumentsObject(Isolate* isolate,
11996 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011997 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011998 Handle<JSFunction> function,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011999 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012000 Handle<Context> function_context) {
12001 // Try to find the value of 'arguments' to pass as parameter. If it is not
12002 // found (that is the debugged function does not reference 'arguments' and
12003 // does not support eval) then create an 'arguments' object.
12004 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012005 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012006 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012007 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012008 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012009 }
12010 }
12011
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012012 if (scope_info->HasHeapAllocatedLocals()) {
12013 VariableMode mode;
12014 InitializationFlag init_flag;
12015 index = scope_info->ContextSlotIndex(
12016 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012017 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012018 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012019 }
12020 }
12021
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012022 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
12023
12024 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012025 Handle<JSObject> arguments =
12026 isolate->factory()->NewArgumentsObject(function, length);
12027 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012028
12029 AssertNoAllocation no_gc;
12030 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012031 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012032 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012033 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012034 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012035 return arguments;
12036}
12037
12038
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012039static const char kSourceStr[] =
12040 "(function(arguments,__source__){return eval(__source__);})";
12041
12042
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012043// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000012044// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012045// extension part has all the parameters and locals of the function on the
12046// stack frame. A function which calls eval with the code to evaluate is then
12047// compiled in this context and called in this context. As this context
12048// replaces the context of the function on the stack frame a new (empty)
12049// function is created as well to be used as the closure for the context.
12050// This function and the context acts as replacements for the function on the
12051// stack frame presenting the same view of the values of parameters and
12052// local variables as if the piece of JavaScript was evaluated at the point
12053// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012054RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012055 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012056
12057 // Check the execution state and decode arguments frame and source to be
12058 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012059 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012060 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012061 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12062 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012063 if (!maybe_check_result->ToObject(&check_result)) {
12064 return maybe_check_result;
12065 }
12066 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012067 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012068 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
12069 CONVERT_ARG_CHECKED(String, source, 3);
12070 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
12071 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012072
12073 // Handle the processing of break.
12074 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012075
12076 // Get the frame where the debugging is performed.
12077 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012078 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012079 JavaScriptFrame* frame = it.frame();
12080 Handle<JSFunction> function(JSFunction::cast(frame->function()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012081 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012082
12083 // Traverse the saved contexts chain to find the active context for the
12084 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012085 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12086
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012087 SaveContext savex(isolate);
12088 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012089
12090 // Create the (empty) function replacing the function on the stack frame for
12091 // the purpose of evaluating in the context created below. It is important
12092 // that this function does not describe any parameters and local variables
12093 // in the context. If it does then this will cause problems with the lookup
12094 // in Context::Lookup, where context slots for parameters and local variables
12095 // are looked at before the extension object.
12096 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012097 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12098 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012099 go_between->set_context(function->context());
12100#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012101 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12102 ASSERT(go_between_scope_info->ParameterCount() == 0);
12103 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012104#endif
12105
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012106 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012107 Handle<JSObject> local_scope = MaterializeLocalScope(
12108 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012109 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012110
12111 // Allocate a new context for the debug evaluation and set the extension
12112 // object build.
12113 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012114 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12115 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012116 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012117 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012118 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012119 Handle<Context> function_context;
12120 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012121 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012122 function_context = Handle<Context>(frame_context->declaration_context());
12123 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012124 context = CopyNestedScopeContextChain(isolate,
12125 go_between,
12126 context,
12127 frame,
12128 inlined_frame_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012129
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012130 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012131 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012132 context =
12133 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012134 }
12135
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012136 // Wrap the evaluation statement in a new function compiled in the newly
12137 // created context. The function has one parameter which has to be called
12138 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012139 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012140 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012141
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012142 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012143 isolate->factory()->NewStringFromAscii(
12144 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012145
12146 // Currently, the eval code will be executed in non-strict mode,
12147 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012148 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012149 Compiler::CompileEval(function_source,
12150 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012151 context->IsGlobalContext(),
12152 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012153 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012154 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012155 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012156
12157 // Invoke the result of the compilation to get the evaluation function.
12158 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012159 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012160 Handle<Object> evaluation_function =
12161 Execution::Call(compiled_function, receiver, 0, NULL,
12162 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012163 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012164
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012165 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012166 frame,
12167 inlined_frame_index,
12168 function,
12169 scope_info,
12170 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012171
12172 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012173 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012174 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012175 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12176 receiver,
12177 ARRAY_SIZE(argv),
12178 argv,
12179 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012180 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012181
12182 // Skip the global proxy as it has no properties and always delegates to the
12183 // real global object.
12184 if (result->IsJSGlobalProxy()) {
12185 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12186 }
12187
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012188 return *result;
12189}
12190
12191
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012192RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012193 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012194
12195 // Check the execution state and decode arguments frame and source to be
12196 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012197 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012198 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012199 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12200 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012201 if (!maybe_check_result->ToObject(&check_result)) {
12202 return maybe_check_result;
12203 }
12204 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012205 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012206 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012207 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012208
12209 // Handle the processing of break.
12210 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012211
12212 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012213 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012214 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012215 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012216 top = top->prev();
12217 }
12218 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012219 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012220 }
12221
12222 // Get the global context now set to the top context from before the
12223 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012224 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012225
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012226 bool is_global = true;
12227
12228 if (additional_context->IsJSObject()) {
12229 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012230 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
12231 isolate->factory()->empty_string(),
12232 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012233 go_between->set_context(*context);
12234 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012235 isolate->factory()->NewFunctionContext(
12236 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012237 context->set_extension(JSObject::cast(*additional_context));
12238 is_global = false;
12239 }
12240
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012241 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012242 // Currently, the eval code will be executed in non-strict mode,
12243 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012244 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012245 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012246 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012247 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012248 Handle<JSFunction>(
12249 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12250 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012251
12252 // Invoke the result of the compilation to get the evaluation function.
12253 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012254 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012255 Handle<Object> result =
12256 Execution::Call(compiled_function, receiver, 0, NULL,
12257 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012258 // Clear the oneshot breakpoints so that the debugger does not step further.
12259 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012260 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012261 return *result;
12262}
12263
12264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012265RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012266 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012267 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012268
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012269 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012270 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012271
12272 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012273 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012274 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12275 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12276 // because using
12277 // instances->set(i, *GetScriptWrapper(script))
12278 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
12279 // already have deferenced the instances handle.
12280 Handle<JSValue> wrapper = GetScriptWrapper(script);
12281 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012282 }
12283
12284 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012285 Handle<JSObject> result =
12286 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012287 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012288 return *result;
12289}
12290
12291
12292// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012293static int DebugReferencedBy(HeapIterator* iterator,
12294 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012295 Object* instance_filter, int max_references,
12296 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012297 JSFunction* arguments_function) {
12298 NoHandleAllocation ha;
12299 AssertNoAllocation no_alloc;
12300
12301 // Iterate the heap.
12302 int count = 0;
12303 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012304 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012305 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012306 (max_references == 0 || count < max_references)) {
12307 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012308 if (heap_obj->IsJSObject()) {
12309 // Skip context extension objects and argument arrays as these are
12310 // checked in the context of functions using them.
12311 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012312 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012313 obj->map()->constructor() == arguments_function) {
12314 continue;
12315 }
12316
12317 // Check if the JS object has a reference to the object looked for.
12318 if (obj->ReferencesObject(target)) {
12319 // Check instance filter if supplied. This is normally used to avoid
12320 // references from mirror objects (see Runtime_IsInPrototypeChain).
12321 if (!instance_filter->IsUndefined()) {
12322 Object* V = obj;
12323 while (true) {
12324 Object* prototype = V->GetPrototype();
12325 if (prototype->IsNull()) {
12326 break;
12327 }
12328 if (instance_filter == prototype) {
12329 obj = NULL; // Don't add this object.
12330 break;
12331 }
12332 V = prototype;
12333 }
12334 }
12335
12336 if (obj != NULL) {
12337 // Valid reference found add to instance array if supplied an update
12338 // count.
12339 if (instances != NULL && count < instances_size) {
12340 instances->set(count, obj);
12341 }
12342 last = obj;
12343 count++;
12344 }
12345 }
12346 }
12347 }
12348
12349 // Check for circular reference only. This can happen when the object is only
12350 // referenced from mirrors and has a circular reference in which case the
12351 // object is not really alive and would have been garbage collected if not
12352 // referenced from the mirror.
12353 if (count == 1 && last == target) {
12354 count = 0;
12355 }
12356
12357 // Return the number of referencing objects found.
12358 return count;
12359}
12360
12361
12362// Scan the heap for objects with direct references to an object
12363// args[0]: the object to find references to
12364// args[1]: constructor function for instances to exclude (Mirror)
12365// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012366RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012367 ASSERT(args.length() == 3);
12368
12369 // First perform a full GC in order to avoid references from dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012370 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
12371 // The heap iterator reserves the right to do a GC to make the heap iterable.
12372 // Due to the GC above we know it won't need to do that, but it seems cleaner
12373 // to get the heap iterator constructed before we start having unprotected
12374 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012375
12376 // Check parameters.
12377 CONVERT_CHECKED(JSObject, target, args[0]);
12378 Object* instance_filter = args[1];
12379 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12380 instance_filter->IsJSObject());
12381 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12382 RUNTIME_ASSERT(max_references >= 0);
12383
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012384
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012385 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012386 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012387 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012388 JSFunction* arguments_function =
12389 JSFunction::cast(arguments_boilerplate->map()->constructor());
12390
12391 // Get the number of referencing objects.
12392 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012393 HeapIterator heap_iterator;
12394 count = DebugReferencedBy(&heap_iterator,
12395 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012396 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012397
12398 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012399 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012400 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012401 if (!maybe_object->ToObject(&object)) return maybe_object;
12402 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012403 FixedArray* instances = FixedArray::cast(object);
12404
12405 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012406 // AllocateFixedArray above does not make the heap non-iterable.
12407 ASSERT(HEAP->IsHeapIterable());
12408 HeapIterator heap_iterator2;
12409 count = DebugReferencedBy(&heap_iterator2,
12410 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012411 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012412
12413 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012414 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012415 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012416 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012417 if (!maybe_result->ToObject(&result)) return maybe_result;
12418 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012419}
12420
12421
12422// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012423static int DebugConstructedBy(HeapIterator* iterator,
12424 JSFunction* constructor,
12425 int max_references,
12426 FixedArray* instances,
12427 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012428 AssertNoAllocation no_alloc;
12429
12430 // Iterate the heap.
12431 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012432 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012433 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012434 (max_references == 0 || count < max_references)) {
12435 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012436 if (heap_obj->IsJSObject()) {
12437 JSObject* obj = JSObject::cast(heap_obj);
12438 if (obj->map()->constructor() == constructor) {
12439 // Valid reference found add to instance array if supplied an update
12440 // count.
12441 if (instances != NULL && count < instances_size) {
12442 instances->set(count, obj);
12443 }
12444 count++;
12445 }
12446 }
12447 }
12448
12449 // Return the number of referencing objects found.
12450 return count;
12451}
12452
12453
12454// Scan the heap for objects constructed by a specific function.
12455// args[0]: the constructor to find instances of
12456// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012457RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012458 ASSERT(args.length() == 2);
12459
12460 // First perform a full GC in order to avoid dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012461 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012462
12463 // Check parameters.
12464 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12465 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12466 RUNTIME_ASSERT(max_references >= 0);
12467
12468 // Get the number of referencing objects.
12469 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012470 HeapIterator heap_iterator;
12471 count = DebugConstructedBy(&heap_iterator,
12472 constructor,
12473 max_references,
12474 NULL,
12475 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012476
12477 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012478 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012479 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012480 if (!maybe_object->ToObject(&object)) return maybe_object;
12481 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012482 FixedArray* instances = FixedArray::cast(object);
12483
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012484 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012485 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012486 HeapIterator heap_iterator2;
12487 count = DebugConstructedBy(&heap_iterator2,
12488 constructor,
12489 max_references,
12490 instances,
12491 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012492
12493 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012494 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012495 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12496 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012497 if (!maybe_result->ToObject(&result)) return maybe_result;
12498 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012499 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012500}
12501
12502
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012503// Find the effective prototype object as returned by __proto__.
12504// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012505RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012506 ASSERT(args.length() == 1);
12507
12508 CONVERT_CHECKED(JSObject, obj, args[0]);
12509
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012510 // Use the __proto__ accessor.
12511 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012512}
12513
12514
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012515RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012516 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012517 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012518 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012519}
12520
12521
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012522RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012523#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012524 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012525 ASSERT(args.length() == 1);
12526 // Get the function and make sure it is compiled.
12527 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012528 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012529 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012530 return Failure::Exception();
12531 }
12532 func->code()->PrintLn();
12533#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012534 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012535}
ager@chromium.org9085a012009-05-11 19:22:57 +000012536
12537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012538RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012539#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012540 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012541 ASSERT(args.length() == 1);
12542 // Get the function and make sure it is compiled.
12543 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012544 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012545 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012546 return Failure::Exception();
12547 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012548 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012549#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012550 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012551}
12552
12553
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012554RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012555 NoHandleAllocation ha;
12556 ASSERT(args.length() == 1);
12557
12558 CONVERT_CHECKED(JSFunction, f, args[0]);
12559 return f->shared()->inferred_name();
12560}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012561
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012562
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012563static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12564 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012565 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012566 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012567 int counter = 0;
12568 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012569 for (HeapObject* obj = iterator->next();
12570 obj != NULL;
12571 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012572 ASSERT(obj != NULL);
12573 if (!obj->IsSharedFunctionInfo()) {
12574 continue;
12575 }
12576 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12577 if (shared->script() != script) {
12578 continue;
12579 }
12580 if (counter < buffer_size) {
12581 buffer->set(counter, shared);
12582 }
12583 counter++;
12584 }
12585 return counter;
12586}
12587
12588// For a script finds all SharedFunctionInfo's in the heap that points
12589// to this script. Returns JSArray of SharedFunctionInfo wrapped
12590// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012591RUNTIME_FUNCTION(MaybeObject*,
12592 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012593 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012594 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012595 CONVERT_CHECKED(JSValue, script_value, args[0]);
12596
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012597
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012598 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12599
12600 const int kBufferSize = 32;
12601
12602 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012603 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012604 int number;
12605 {
12606 isolate->heap()->EnsureHeapIsIterable();
12607 AssertNoAllocation no_allocations;
12608 HeapIterator heap_iterator;
12609 Script* scr = *script;
12610 FixedArray* arr = *array;
12611 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12612 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012613 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012614 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012615 isolate->heap()->EnsureHeapIsIterable();
12616 AssertNoAllocation no_allocations;
12617 HeapIterator heap_iterator;
12618 Script* scr = *script;
12619 FixedArray* arr = *array;
12620 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012621 }
12622
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012623 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012624 result->set_length(Smi::FromInt(number));
12625
12626 LiveEdit::WrapSharedFunctionInfos(result);
12627
12628 return *result;
12629}
12630
12631// For a script calculates compilation information about all its functions.
12632// The script source is explicitly specified by the second argument.
12633// The source of the actual script is not used, however it is important that
12634// all generated code keeps references to this particular instance of script.
12635// Returns a JSArray of compilation infos. The array is ordered so that
12636// each function with all its descendant is always stored in a continues range
12637// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012638RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012639 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012640 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012641 CONVERT_CHECKED(JSValue, script, args[0]);
12642 CONVERT_ARG_CHECKED(String, source, 1);
12643 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12644
12645 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12646
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012647 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012648 return Failure::Exception();
12649 }
12650
12651 return result;
12652}
12653
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012654// Changes the source of the script to a new_source.
12655// If old_script_name is provided (i.e. is a String), also creates a copy of
12656// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012657RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012658 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012659 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012660 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12661 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012662 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012663
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012664 CONVERT_CHECKED(Script, original_script_pointer,
12665 original_script_value->value());
12666 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012667
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012668 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12669 new_source,
12670 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012671
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012672 if (old_script->IsScript()) {
12673 Handle<Script> script_handle(Script::cast(old_script));
12674 return *(GetScriptWrapper(script_handle));
12675 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012676 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012677 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012678}
12679
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012680
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012681RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012682 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012683 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012684 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12685 return LiveEdit::FunctionSourceUpdated(shared_info);
12686}
12687
12688
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012689// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012690RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012691 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012692 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012693 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12694 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12695
ager@chromium.orgac091b72010-05-05 07:34:42 +000012696 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012697}
12698
12699// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012700RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012701 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012702 HandleScope scope(isolate);
12703 Handle<Object> function_object(args[0], isolate);
12704 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012705
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012706 if (function_object->IsJSValue()) {
12707 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12708 if (script_object->IsJSValue()) {
12709 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012710 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012711 }
12712
12713 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12714 } else {
12715 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12716 // and we check it in this function.
12717 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012718
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012719 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012720}
12721
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012722
12723// In a code of a parent function replaces original function as embedded object
12724// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012725RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012726 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012727 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012728
12729 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12730 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12731 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12732
12733 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12734 subst_wrapper);
12735
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012736 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012737}
12738
12739
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012740// Updates positions of a shared function info (first parameter) according
12741// to script source change. Text change is described in second parameter as
12742// array of groups of 3 numbers:
12743// (change_begin, change_end, change_end_new_position).
12744// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012745RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012746 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012747 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012748 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12749 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12750
ager@chromium.orgac091b72010-05-05 07:34:42 +000012751 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012752}
12753
12754
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012755// For array of SharedFunctionInfo's (each wrapped in JSValue)
12756// checks that none of them have activations on stacks (of any thread).
12757// Returns array of the same length with corresponding results of
12758// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012759RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012760 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012761 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012762 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012763 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012764
ager@chromium.org357bf652010-04-12 11:30:10 +000012765 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012766}
12767
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012768// Compares 2 strings line-by-line, then token-wise and returns diff in form
12769// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12770// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012771RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012772 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012773 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012774 CONVERT_ARG_CHECKED(String, s1, 0);
12775 CONVERT_ARG_CHECKED(String, s2, 1);
12776
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012777 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012778}
12779
12780
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012781// A testing entry. Returns statement position which is the closest to
12782// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012783RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012784 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012785 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012786 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12787 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12788
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012789 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012790
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012791 if (code->kind() != Code::FUNCTION &&
12792 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012793 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012794 }
12795
12796 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012797 int closest_pc = 0;
12798 int distance = kMaxInt;
12799 while (!it.done()) {
12800 int statement_position = static_cast<int>(it.rinfo()->data());
12801 // Check if this break point is closer that what was previously found.
12802 if (source_position <= statement_position &&
12803 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012804 closest_pc =
12805 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012806 distance = statement_position - source_position;
12807 // Check whether we can't get any closer.
12808 if (distance == 0) break;
12809 }
12810 it.next();
12811 }
12812
12813 return Smi::FromInt(closest_pc);
12814}
12815
12816
ager@chromium.org357bf652010-04-12 11:30:10 +000012817// Calls specified function with or without entering the debugger.
12818// This is used in unit tests to run code as if debugger is entered or simply
12819// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012820RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012821 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012822 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012823 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12824 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12825
12826 Handle<Object> result;
12827 bool pending_exception;
12828 {
12829 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012830 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012831 &pending_exception);
12832 } else {
12833 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012834 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012835 &pending_exception);
12836 }
12837 }
12838 if (!pending_exception) {
12839 return *result;
12840 } else {
12841 return Failure::Exception();
12842 }
12843}
12844
12845
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012846// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012847RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012848 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012849 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012850 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12851 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012852 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012853}
12854
12855
12856// Performs a GC.
12857// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012858RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012859 isolate->heap()->CollectAllGarbage(true);
12860 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012861}
12862
12863
12864// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012865RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012866 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012867 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012868 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012869 }
12870 return Smi::FromInt(usage);
12871}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012872
12873
12874// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012875RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012876#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012877 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012878#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012879 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012880#endif
12881}
12882
12883
12884// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012885RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012886#ifdef LIVE_OBJECT_LIST
12887 return LiveObjectList::Capture();
12888#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012889 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012890#endif
12891}
12892
12893
12894// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012895RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012896#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012897 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012898 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012899 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012900#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012901 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012902#endif
12903}
12904
12905
12906// Generates the response to a debugger request for a dump of the objects
12907// contained in the difference between the captured live object lists
12908// specified by id1 and id2.
12909// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12910// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012911RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012912#ifdef LIVE_OBJECT_LIST
12913 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012914 CONVERT_SMI_ARG_CHECKED(id1, 0);
12915 CONVERT_SMI_ARG_CHECKED(id2, 1);
12916 CONVERT_SMI_ARG_CHECKED(start, 2);
12917 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012918 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12919 EnterDebugger enter_debugger;
12920 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12921#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012922 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012923#endif
12924}
12925
12926
12927// Gets the specified object as requested by the debugger.
12928// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012929RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012930#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012931 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012932 Object* result = LiveObjectList::GetObj(obj_id);
12933 return result;
12934#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012935 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012936#endif
12937}
12938
12939
12940// Gets the obj id for the specified address if valid.
12941// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012942RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012943#ifdef LIVE_OBJECT_LIST
12944 HandleScope scope;
12945 CONVERT_ARG_CHECKED(String, address, 0);
12946 Object* result = LiveObjectList::GetObjId(address);
12947 return result;
12948#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012949 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012950#endif
12951}
12952
12953
12954// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012955RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012956#ifdef LIVE_OBJECT_LIST
12957 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012958 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012959 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12960 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12961 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12962 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12963 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12964
12965 Handle<JSObject> instance_filter;
12966 if (args[1]->IsJSObject()) {
12967 instance_filter = args.at<JSObject>(1);
12968 }
12969 bool verbose = false;
12970 if (args[2]->IsBoolean()) {
12971 verbose = args[2]->IsTrue();
12972 }
12973 int start = 0;
12974 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012975 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012976 }
12977 int limit = Smi::kMaxValue;
12978 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012979 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012980 }
12981
12982 return LiveObjectList::GetObjRetainers(obj_id,
12983 instance_filter,
12984 verbose,
12985 start,
12986 limit,
12987 filter_obj);
12988#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012989 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012990#endif
12991}
12992
12993
12994// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012995RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012996#ifdef LIVE_OBJECT_LIST
12997 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012998 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12999 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013000 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
13001
13002 Handle<JSObject> instance_filter;
13003 if (args[2]->IsJSObject()) {
13004 instance_filter = args.at<JSObject>(2);
13005 }
13006
13007 Object* result =
13008 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
13009 return result;
13010#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013011 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013012#endif
13013}
13014
13015
13016// Generates the response to a debugger request for a list of all
13017// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013018RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013019#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013020 CONVERT_SMI_ARG_CHECKED(start, 0);
13021 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013022 return LiveObjectList::Info(start, count);
13023#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013024 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013025#endif
13026}
13027
13028
13029// Gets a dump of the specified object as requested by the debugger.
13030// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013031RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013032#ifdef LIVE_OBJECT_LIST
13033 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013034 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013035 Object* result = LiveObjectList::PrintObj(obj_id);
13036 return result;
13037#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013038 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013039#endif
13040}
13041
13042
13043// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013044RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013045#ifdef LIVE_OBJECT_LIST
13046 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013047 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013048#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013049 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013050#endif
13051}
13052
13053
13054// Generates the response to a debugger request for a summary of the types
13055// of objects in the difference between the captured live object lists
13056// specified by id1 and id2.
13057// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13058// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013059RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013060#ifdef LIVE_OBJECT_LIST
13061 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013062 CONVERT_SMI_ARG_CHECKED(id1, 0);
13063 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013064 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
13065
13066 EnterDebugger enter_debugger;
13067 return LiveObjectList::Summarize(id1, id2, filter_obj);
13068#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013069 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013070#endif
13071}
13072
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013073#endif // ENABLE_DEBUGGER_SUPPORT
13074
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013075
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013076RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013077 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013078 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013079 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013080}
13081
13082
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013083RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013084 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013085 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013086 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013087}
13088
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013089
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013090// Finds the script object from the script data. NOTE: This operation uses
13091// heap traversal to find the function generated for the source position
13092// for the requested break point. For lazily compiled functions several heap
13093// traversals might be required rendering this operation as a rather slow
13094// operation. However for setting break points which is normally done through
13095// some kind of user interaction the performance is not crucial.
13096static Handle<Object> Runtime_GetScriptFromScriptName(
13097 Handle<String> script_name) {
13098 // Scan the heap for Script objects to find the script with the requested
13099 // script data.
13100 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013101 script_name->GetHeap()->EnsureHeapIsIterable();
13102 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013103 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013104 HeapObject* obj = NULL;
13105 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013106 // If a script is found check if it has the script data requested.
13107 if (obj->IsScript()) {
13108 if (Script::cast(obj)->name()->IsString()) {
13109 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13110 script = Handle<Script>(Script::cast(obj));
13111 }
13112 }
13113 }
13114 }
13115
13116 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013117 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013118
13119 // Return the script found.
13120 return GetScriptWrapper(script);
13121}
13122
13123
13124// Get the script object from script data. NOTE: Regarding performance
13125// see the NOTE for GetScriptFromScriptData.
13126// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013127RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013128 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013129
13130 ASSERT(args.length() == 1);
13131
13132 CONVERT_CHECKED(String, script_name, args[0]);
13133
13134 // Find the requested script.
13135 Handle<Object> result =
13136 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13137 return *result;
13138}
13139
13140
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013141// Determines whether the given stack frame should be displayed in
13142// a stack trace. The caller is the error constructor that asked
13143// for the stack trace to be collected. The first time a construct
13144// call to this function is encountered it is skipped. The seen_caller
13145// in/out parameter is used to remember if the caller has been seen
13146// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013147static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13148 Object* caller,
13149 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013150 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013151 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013152 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013153 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013154 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13155 Object* raw_fun = frame->function();
13156 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013157 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013158 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013159 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013160 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013161 *seen_caller = true;
13162 return false;
13163 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013164 // Skip all frames until we've seen the caller.
13165 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013166 // Also, skip non-visible built-in functions and any call with the builtins
13167 // object as receiver, so as to not reveal either the builtins object or
13168 // an internal function.
13169 // The --builtins-in-stack-traces command line flag allows including
13170 // internal call sites in the stack trace for debugging purposes.
13171 if (!FLAG_builtins_in_stack_traces) {
13172 JSFunction* fun = JSFunction::cast(raw_fun);
13173 if (frame->receiver()->IsJSBuiltinsObject() ||
13174 (fun->IsBuiltin() && !fun->shared()->native())) {
13175 return false;
13176 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013177 }
13178 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013179}
13180
13181
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013182// Collect the raw data for a stack trace. Returns an array of 4
13183// element segments each containing a receiver, function, code and
13184// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013185RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013186 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013187 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013188 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
13189
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013190 HandleScope scope(isolate);
13191 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013192
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013193 limit = Max(limit, 0); // Ensure that limit is not negative.
13194 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013195 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013196 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013197
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013198 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013199 // If the caller parameter is a function we skip frames until we're
13200 // under it before starting to collect.
13201 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013202 int cursor = 0;
13203 int frames_seen = 0;
13204 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013205 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013206 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013207 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013208 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013209 // Set initial size to the maximum inlining level + 1 for the outermost
13210 // function.
13211 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013212 frame->Summarize(&frames);
13213 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013214 if (cursor + 4 > elements->length()) {
13215 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13216 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013217 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013218 for (int i = 0; i < cursor; i++) {
13219 new_elements->set(i, elements->get(i));
13220 }
13221 elements = new_elements;
13222 }
13223 ASSERT(cursor + 4 <= elements->length());
13224
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013225 Handle<Object> recv = frames[i].receiver();
13226 Handle<JSFunction> fun = frames[i].function();
13227 Handle<Code> code = frames[i].code();
13228 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013229 elements->set(cursor++, *recv);
13230 elements->set(cursor++, *fun);
13231 elements->set(cursor++, *code);
13232 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013233 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013234 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013235 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013236 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013237 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013238 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013239 return *result;
13240}
13241
13242
ager@chromium.org3811b432009-10-28 14:53:37 +000013243// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013244RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013245 ASSERT_EQ(args.length(), 0);
13246
13247 NoHandleAllocation ha;
13248
13249 const char* version_string = v8::V8::GetVersion();
13250
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013251 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13252 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013253}
13254
13255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013256RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013257 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013258 OS::PrintError("abort: %s\n",
13259 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013260 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013261 OS::Abort();
13262 UNREACHABLE();
13263 return NULL;
13264}
13265
13266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013267RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013268 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013269 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013270 Object* key = args[1];
13271
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013272 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013273 Object* o = cache->get(finger_index);
13274 if (o == key) {
13275 // The fastest case: hit the same place again.
13276 return cache->get(finger_index + 1);
13277 }
13278
13279 for (int i = finger_index - 2;
13280 i >= JSFunctionResultCache::kEntriesIndex;
13281 i -= 2) {
13282 o = cache->get(i);
13283 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013284 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013285 return cache->get(i + 1);
13286 }
13287 }
13288
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013289 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013290 ASSERT(size <= cache->length());
13291
13292 for (int i = size - 2; i > finger_index; i -= 2) {
13293 o = cache->get(i);
13294 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013295 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013296 return cache->get(i + 1);
13297 }
13298 }
13299
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013300 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013301 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013302
13303 Handle<JSFunctionResultCache> cache_handle(cache);
13304 Handle<Object> key_handle(key);
13305 Handle<Object> value;
13306 {
13307 Handle<JSFunction> factory(JSFunction::cast(
13308 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13309 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013310 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013311 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013312 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013313 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013314 value = Execution::Call(factory,
13315 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013316 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013317 argv,
13318 &pending_exception);
13319 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013320 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013321
13322#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013323 if (FLAG_verify_heap) {
13324 cache_handle->JSFunctionResultCacheVerify();
13325 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013326#endif
13327
13328 // Function invocation may have cleared the cache. Reread all the data.
13329 finger_index = cache_handle->finger_index();
13330 size = cache_handle->size();
13331
13332 // If we have spare room, put new data into it, otherwise evict post finger
13333 // entry which is likely to be the least recently used.
13334 int index = -1;
13335 if (size < cache_handle->length()) {
13336 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13337 index = size;
13338 } else {
13339 index = finger_index + JSFunctionResultCache::kEntrySize;
13340 if (index == cache_handle->length()) {
13341 index = JSFunctionResultCache::kEntriesIndex;
13342 }
13343 }
13344
13345 ASSERT(index % 2 == 0);
13346 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13347 ASSERT(index < cache_handle->length());
13348
13349 cache_handle->set(index, *key_handle);
13350 cache_handle->set(index + 1, *value);
13351 cache_handle->set_finger_index(index);
13352
13353#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013354 if (FLAG_verify_heap) {
13355 cache_handle->JSFunctionResultCacheVerify();
13356 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013357#endif
13358
13359 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013360}
13361
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013362
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013363RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013364 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013365 CONVERT_ARG_CHECKED(String, type, 0);
13366 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013367 return *isolate->factory()->NewJSMessageObject(
13368 type,
13369 arguments,
13370 0,
13371 0,
13372 isolate->factory()->undefined_value(),
13373 isolate->factory()->undefined_value(),
13374 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013375}
13376
13377
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013378RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013379 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13380 return message->type();
13381}
13382
13383
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013384RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013385 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13386 return message->arguments();
13387}
13388
13389
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013390RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013391 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13392 return Smi::FromInt(message->start_position());
13393}
13394
13395
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013396RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013397 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13398 return message->script();
13399}
13400
13401
kasper.lund44510672008-07-25 07:37:58 +000013402#ifdef DEBUG
13403// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13404// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013405RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013406 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013407 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013408#define COUNT_ENTRY(Name, argc, ressize) + 1
13409 int entry_count = 0
13410 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13411 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13412 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13413#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013414 Factory* factory = isolate->factory();
13415 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013416 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013417 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013418#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013419 { \
13420 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013421 Handle<String> name; \
13422 /* Inline runtime functions have an underscore in front of the name. */ \
13423 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013424 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013425 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13426 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013427 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013428 Vector<const char>(#Name, StrLength(#Name))); \
13429 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013430 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013431 pair_elements->set(0, *name); \
13432 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013433 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013434 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013435 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013436 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013437 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013438 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013439 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013440 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013441#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013442 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013443 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013444 return *result;
13445}
kasper.lund44510672008-07-25 07:37:58 +000013446#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013447
13448
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013449RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013450 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013451 CONVERT_CHECKED(String, format, args[0]);
13452 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013453 String::FlatContent format_content = format->GetFlatContent();
13454 RUNTIME_ASSERT(format_content.IsAscii());
13455 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013456 LOGGER->LogRuntime(chars, elms);
13457 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013458}
13459
13460
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013461RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013462 UNREACHABLE(); // implemented as macro in the parser
13463 return NULL;
13464}
13465
13466
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013467#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13468 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13469 CONVERT_CHECKED(JSObject, obj, args[0]); \
13470 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13471 }
13472
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013473ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013474ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13475ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13476ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13477ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13478ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13479ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13480ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13481ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13482ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13483ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13484ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13485ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13486ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13487
13488#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13489
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013490
13491RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13492 ASSERT(args.length() == 2);
13493 CONVERT_CHECKED(JSObject, obj1, args[0]);
13494 CONVERT_CHECKED(JSObject, obj2, args[1]);
13495 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13496}
13497
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013498// ----------------------------------------------------------------------------
13499// Implementation of Runtime
13500
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013501#define F(name, number_of_args, result_size) \
13502 { Runtime::k##name, Runtime::RUNTIME, #name, \
13503 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013504
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013505
13506#define I(name, number_of_args, result_size) \
13507 { Runtime::kInline##name, Runtime::INLINE, \
13508 "_" #name, NULL, number_of_args, result_size },
13509
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013510static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013511 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013512 INLINE_FUNCTION_LIST(I)
13513 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013514};
13515
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013516
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013517MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13518 Object* dictionary) {
13519 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013520 ASSERT(dictionary != NULL);
13521 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13522 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013523 Object* name_symbol;
13524 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013525 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013526 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13527 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013528 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013529 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13530 String::cast(name_symbol),
13531 Smi::FromInt(i),
13532 PropertyDetails(NONE, NORMAL));
13533 if (!maybe_dictionary->ToObject(&dictionary)) {
13534 // Non-recoverable failure. Calling code must restart heap
13535 // initialization.
13536 return maybe_dictionary;
13537 }
13538 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013539 }
13540 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013541}
13542
13543
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013544const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13545 Heap* heap = name->GetHeap();
13546 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013547 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013548 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013549 int function_index = Smi::cast(smi_index)->value();
13550 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013551 }
13552 return NULL;
13553}
13554
13555
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013556const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013557 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13558}
13559
13560
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013561void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013562 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013563 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013564 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013565 if (isolate->heap()->new_space()->AddFreshPage()) {
13566 return;
13567 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013568 // Try to do a garbage collection; ignore it if it fails. The C
13569 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013570 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013571 } else {
13572 // Handle last resort GC and make sure to allow future allocations
13573 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013574 isolate->counters()->gc_last_resort_from_js()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013575 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013576 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013577}
13578
13579
13580} } // namespace v8::internal